Background: I am trying to fix two annoyances in the appearance of the audio element in Chrome and while attempting to do so I came across two issues I would like to understand better. This is about Chrome 89 on MacOS. I nicely manage to style inside the audio element, using pseudo selectors. Finding out about the names of the pseudo selectors works nicely when looking inside of the shadow dom with the dom inspector. For example, the following two rules work exactly as expected:
::-webkit-media-controls-timeline {background-color:pink;}
audio::-webkit-media-controls-time-remaining-display {background-color:lightgrey;}
Question: However, two things do not work as expected and I want to understand why.
Problem 1: Styling the first letter in the remaining-display div does not work. The following rule is not effective.
audio::-webkit-media-controls-time-remaining-display:first-letter {color:white;}
This is astonishing, since the browser dispplays this
<style>div:first-letter {color:red;}</style> ... <div>e xample</div>
as expected. Why would I be unable to style the first letter? (The idea of this is to get rid of the most annoying leading / symbol in the remaining time display).
Problem 2:
Why would I be unable to style an element with a different pseudo attribute in a different part of the shadow DOM. More precisely the following rule is not effective:
::-internal-track-segment-highlight-before {background-color: blue;}
I see no difference to the other case above where the color styling worked. (The idea of this is to increase the too small contrast between two parts of the track segment.)
Add on: I managed to improved the contrast a bit using
audio::-webkit-media-controls-timeline {-webkit-filter: brightness(2.5);}
but the issue remains why the one method worked and the other did not work.
You are using Chrome, with "Show user agent shadow DOM" turned on
There are 2 types of shadowDOM
let's call it "userland" shadowDOM,
the (open or closed) shadowDOM created by a (3rd party developer) Custom Element/Web Component
This type is available since the W3C Web Components standard was implemented
"user-agent" shadowDOM created by each Browser (Vendor),
implementing input , audio , video, select etc. tags
but each Browser can have a different implementation.
This shadowDOM content can only be accessed if the Browser vendor has enabled access. (with shadowParts or related tech)
And in general it can not be accessed.
WebKit does have some pseudo selectors to change some settings
See: Is it possible to style html5 audio tag?
But they are not CSS selectors that get you full access to shadowDOM by creating complex selectors.
Some Font and Styling settings do cascade into shadowDOM only to have a consistent style in the whole page.
See: https://lamplightdev.com/blog/2019/03/26/why-is-my-web-component-inheriting-styles/
So that is why your color:red works, and :first-letter doesn't
That is why filter works; and background-color doesn't
alternative
https://github.com/dascritch/cpu-audio is a decent Web Component replacing the standard <audio> tag, that gets you styling in all browsers
Note the notation: (open) not (user-agent)
video::-webkit-media-controls-timeline {
background-color: blue !important;
}
work better for highter contrast.
(tested in video tag)
Related
After carefully reading all related articles and posts on many sites, there is still one remaining question: Can i have a single, exchangeable CSS for a web app built with web components widhtout having to deal with all the weird stuff suggested by W3C?
I know about ::part( something ) and exportparts="something" to access nested components, but that does not go down the tree, so I have to add a part attribute to almost every element, which totally bloats my HTML.
Having an #import rule in each component is also not a great option, because it would be one more HTTP request per stylesheet. Also, once loaded in a template, the importet css can not be exchanged easily.
W3C really makes our lives harder by removing /deep/ and ::shadow. I know, performance concerns, blah, blah, but at least that worked like a charm.
Possible solutions I find impractical:
How to style slotted parts from the parent downwards
::slotted CSS selector for nested children in shadowDOM slot
How to access elements inner two shadow dom
Example HTML where all nested elements would be styleable with global CSS:
<body>
<o-app>
#shadowDOM
<o-header exportparts="username:o-textinput__username,action-ok:o-action__action-ok,o-action__label" part="o-header">
#shadowDOM
<o-texinput part="username">
<o-action exportparts="label:o-action__label" part="action-ok">
#shadowDOM
<div part="label">
Then I can finally style the label div by selecting it with:
::part( o-action__label ) {}
Now tell me that having to specify every single part of all descendant elements in the parent elements is not a total mess!
Playaround on Codepen: https://codepen.io/5180/pen/jOyQNYq?editors=1111
Now in 2021 I would rather use light DOM only instead of forcing the shadow DOM to behave like its counterpart, because there is currently no easy method of piercing through the artificial boundary. It was in the spec – ::shadow and /deep/ – but got removed, so deal with it. ::theme() is not ready yet, The ::part() selector is useless for deep styling as I pointed out in my example.
Just use the light DOM (innerHTML) of your custom element to avoid deep styling/theming issues.
I should start off by saying that I don't really have an issue that I'm trying to work through. I just had an interesting thought about how Shadow Dom and the CSS3 :target selector might / should / currently do work together.
I know that HTML specification says that there should only ever be one element with a particular ID value in a valid HTML document. But when we start using webcomponents with shadow dom we could very easily find ourselves using multiple elements with the same ID. This is especially true when we use the same component multiple times in the same page. So the question that I have is this: what should happen to an element inside a shadow dom region that has an ID value which matches the current hash and which is styled with a :target rule?
For example, if I wrote a webcomponent (my-element) that contained
<style>
#debug {display:none}
#debug:target { display:block; background-color:yellow; border 2px solid red; }
</style>
<div id="debug">some debug data</div>
What should happen to all the instance of my-element that I put on a page and navigated to #debug on? Should the debug element in each component show? Should none of them show? Should only the first element's debug div show (the same one I'd expect the browser to try and navigate to)?
My opinion is that if the page does not have an element with an ID=debug value that no scrolling navigation should appear on the page. As shadow dom is isolated from the rest of the page's styles the browser shouldn't try to navigate to such an element nested in shadow dom. Each my-element instance should be able to see the current page's URL though and should apply any matching :target rules, such that each my-elements' debug div should be visible.
If this were the case it would make for some interesting possibilities for sharing page state across all components, such as the debug example above. However, I doubt that is how Chrome is currently implementing things. And I'm pretty sure this Shadow Dom polyfill isn't going to handle things correctly as it basically shoehorns everything into the page's Dom tree and that would break the html specification.
Just curious if anyone has an answer for how this should work and how it works today...
(edited from my pc to add formatting... hard to do from my phone)
I think you can see the shadow DOM like a nested document. CSS can't address elements inside the shadow DOM from the outside (previously existing shadow piercing CSS selectors were deprecated).
This also encapsulates ids and therefore multiple components that contain elements with an id won't cause collisions or duplicates.
If you have the CSS with the :target selector inside a components style, it should be able to address the element with the matching id, otherwise it shouldn't.
So the question that I have is this: what should happen to an element
inside a shadow dom region that has an ID value which matches the
current hash and which is styled with a :target rule?
Adding to Günter Zöchbauer above answer an alternative is to use the Custom Element object when the style is encapsulated, if the style is global it will work just fine. Use the define method to create a custom component as shown in the the docs. This will not encapsulate your elements so be aware that your styles can be shared across files.
So instead of doing this:
const shadow = this.attachShadow({ mode: "open" });
shadow.appendChild(pTag)
Use this:
this.appendChild(pTag);
both previous examples suppose you're in a HTMLElement class or a class that inherits it.
Here is my code:
.blue {
color:#6E99E1;
font-size:9px;
}
<span class="blue">::CLICK HERE:: to view our New Equipment inventory. <br /><br /></span>
I've somehow triggered something that prevented the <a> tag from inheriting color of parent <span>.
Just an addendum to the other responses, if you want your <a> tags to inherit the colour from their parent you can use
a {color: inherit; }
By default an anchor tag does not inherit attributes like color if an href attribute is present.
Check out the difference between these two on a page:
<span style=color:green>test</span>
<span style=color:green><a>test</a></span>
The following link is to the w3 c:
http://www.w3.org/TR/html401/struct/links.html#h-12.2
User agents generally render links in
such a way as to make them obvious to
users (underlining, reverse video,
etc.). The exact rendering depends on
the user agent. Rendering may vary
according to whether the user has
already visited the link or not.
.....
Usually, the contents of A are not
rendered in any special way when A
defines an anchor only.
This is an answer to the question as well as a reply to Kevin's answer and its comments.
Anchor tags do inherit color, linked or not. The only reason they don't in practice is because they already have their color set in the browser's default stylesheet. The same can be said for the underlining of the link (which, I presume, you didn't notice, because you actually want it or had already changed it yourself).
In Firefox, you can see this in Firebug if you toggle "Show User Agent CSS" (or you can have a look at Firefox's internal stylesheets directly. You can see the browser's defaults in Webkit's Web Inspector and Opera's Dragonfly as well. I don't think you can in IE.
I don't know of any site which has an overview of all browser's defaults. CSS2's "informative" HTML4 stylesheet as well as the YUI reset stylesheet would be a good starting point, but neither of them mention any (link) colors (the HTML4 stylesheet does mention the underline).
To find out which properties are inherited in general, you can use the CSS2 reference property index table (see the "Inherited?" column). SitePoint also mentions it in its CSS reference.
So if you want to make sure your link inherits its color from its parent instead of from the browser's default stylesheet, you would ideally do something like this:
.blue a:link {
color: inherit;
}
You could set it for the different pseudo-classes separately (so :visited, :hover and :active as well), or for the a tag altogether.
However, IE6 and IE7 don't support the inherit keyword, so if you want to support them too, you'd have to set the color explicitly.
I think a doesn't inherit color by default. (certainly it has always worked that way on my sites). Why not change
.blue {
color:#6E99E1;
font-size:9px;
}
to
.blue, .blue a{
color:#6E99E1;
font-size:9px;
}
Firebug will show you exactly which style rules are applied to which elements. It's perfect for this.
(A non-CSS possibility: Do you have link/alink/vlink attributes on your <body> tag?)
Edit: Duh, silly me, the others have it right - <a href> doesn't inherit colour. But Firebug is still a good tool for this kind of problem (even if I'm not. 8-)
In addition to firebug (which should be your first port of call), the IE developer toolbar will also tell you where a given style is sourced from, just in case IE - shock, horror - should be different.
You need to explicitly set the color of the links to override the default blue color.
You are likely seeing the a:visited colouring. Try this:
.blue, .blue:link, .blue:visited {
color:#6E99E1;
font-size:9px;
}
In our application we use Bootstrap and there are multiple CSS files that are used.
Recently, I had a issue where there was a border created around a input box. The border for the CSS for input types were over-ridden in a particular CSS file.
I tried to use the Chrome DEV tools to identify which CSS file that input box was picking (for color) but for some reason it was not identifying the correct CSS files. For borders, shape and size it was mentioning it was inheriting from the parent but it never mentioning which is the parent CSS file.
Is there a better tool which correctly points the CSS that the component is using?
Is there a better tool which correctly points the css that the
component is using?
Firebug is great & very well developed. But works only in FireFox, which should not be a big deal for your basic CSS debugging purposes. In general there is no one good tool to debug things like this. You will always be jumping around from tool to tool to get things right. It’s just the nature of front-end web development.
But in general, might not have to even touch the parent CSS to deal with this issue. Just target the element in CSS—if it is not already being targeted—and use !important to force your new setting to override others from parent styles.
However, for balance, an "!important" declaration (the delimiter token
"!" and keyword "important" follow the declaration) takes precedence
over a normal declaration. Both author and user style sheets may
contain "!important" declarations, and user "!important" rules
override author "!important" rules. This CSS feature improves
accessibility of documents by giving users with special requirements
(large fonts, color combinations, etc.) control over presentation.
Here is an example code that would force outline: none to all input elements:
input {
outline: none; !important
}
You can even add border: 0px solid; to the mix as well:
input {
border: 0px solid; !important
outline: none; !important
}
I tried to use the Chrome DEV tools to identify which CSS file that input box was picking (for color) but for some reason it was not identifying the correct CSS files. For borders, shape and size it was mentioning it was inheriting from the parent but it never mentioning which is the parent CSS file.
In general Chrome Developer Tools shows exactly which .css-files are used and from which element the styles are inherited.
Can you maybe provide an example with your exact problem?
I plan on using some of the new HTML5 semantic elements, but it looks like some of them aren't well supported even on newer browsers (main isn't supported in IE11 as far as I can tell) is there a way to have them be treated as a <div> if they aren't supported, as the HTML5 semantic tags I plan on using are currently basically the same as divs AFAIK (header, footer, main are the ones I currently plan on using, also canvas but there isn't a good alternative tag to do what canvas does).
Currently if I use one of the unsupported tags in IE it seems to be treated as an unstyled tag but the issue is I can't set the width or height of it in css. What can I do for it to be treated as a and apply all styles that I put in css to that element using the name of the tag as the selector as though it were a <div>.
main
{
width: 100px;
}
does not work in IE11, if it was IE7 or something I wouldn't be too worried but quite a lot of people still use more updated versions of IE and I don't want the website to display improperly to them.
You need the HTML5 shim for supporting older browsers but using just the HTML5 shim does not fix IE11 see: http://jsfiddle.net/jbowyers/n3qZp/. So you also need a CSS reset that includes the 'main' element such as normalize. Or you can just add the CSS reset directly to your project as mentioned by others
main { display: block;}
The html5shiv will allow you to style the main element in IE 11 (and less). There's an explanation of what it does (actually a breakdown of its entire history) here.
Money quote:
Btw, if you want CSS rules to apply to unknown elements in IE, you
just have to do document.createElement(elementName). This somehow lets
the CSS engine know that elements with that name exist
NB. You should probably be using the shiv as a matter of course if you're using HTML5 and plan to support anything less than IE 9.
I think I have found a solution.
In my css file if I do:
main /*or any other unsupported tag that you want treated as a div*/
{
display:block;
other-property:other-value;
other-property:other-value;
...
}
It seems to act identical to a <div> tag. I haven't thoroughly tested or researched this solution (tested several attributes including color, width and text-decoration on IE11 and google chrome with tag named <asdasd> and it worked exactly like a <div>) so if anyone knows any problems with it please let me know.
I’m not sure what the question really is, but the title “Use <div> as backup tag for HTML5 semantic elements” is a good answer to the question “How can I use the HTML5 main, header etc. tags to that my page also works on browsers that do not support them?”
For example, instead of having just <main>...</main> in HTML and main { ... } in CSS, you would have
<div class=main>
<main>...</main>
</div>
in HTML and
.main { ... }
in CSS.
This may look redundant, and you get almost the same browser coverage by using polyfill like html5shiv and explicitly declaring main { display: block } if the polyfill doesn’t do that. But in this approach, you do all the styling in an old robust way and use the new elements only for their semantics. (In reality, the “semantics” means nothing, but maybe some day some programs will recognize main, article etc. and deal with them in some special way.)