CSS pseudo :dir(); :host-context() and directionality based styling - css

In this question I'm looking for the cleanest possible solution for the problem below, along with urging the browsers' coders to catch up with the spec, especially :dir() one!!
The problem and it's current best known to me solution:
I'd like to style the image below based on directionality, flipping it, for example, when in RTL mode. The image resides in a shadow DOM. As of now, I'm achieving that with the styling below.
::shadowRoot
<style>
.directed-image:dir(rtl) { transform: rotateY(180deg); } -- Firefox only as of now
:host-context([dir=rtl]) { transform: rotateY(180deg); } -- Chromium only as of now
</style>
<img class="directed-image" src="..." />
Issues yet to be solved:
None of the styles above helping Safari: it has not yet implemented :dir() pseudo class and it's people seems to have a strong objection to :host-context()
I'm really not fan of those double-done solutions for a platform's diversity; would like to get rid of those, but this is only a secondary concern
Solutions ?:
The best I'd wish to have is that :dir() will get wide cross browser support - it'll solve the Safari's issue as well as would provide a truly directionality context aware styling (downsides of [dir=ltr] are touched a bit in the WebKit's bug link above).
But given that
Chromium's bug on :dir() is staled from 2018
WebKit's bug on :dir() last touched at 2016!!!
Firefox's bug on :host-context() is staled from 2018 with some concerns about the spec
and unwillingness of WebKit to implement :host-context()
-- having all this: is there any other solution for the problem (looking to solve the Safari issue at first priority).
JS based solutions are interesting but much less preferred.

january 2020 answer:
As you said: the dir attribute on the body tag will (in most cases) be the only indication of a language change. Since CSS doesn't cascade (yet; as you said) the only option for now is for Elements to observe that attribute change. So I fear your only option is a MutationObserver (in the elements you own)
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: false, subtree: false };

Not sure if this is what you are looking for, but you could use RTLCSS. It's a CSS framework that allows you to easily switch between and create RTL and LTR stylesheets, without having to do too much double work.
It also supports a couple of big CSS frameworks if you use those, like Bootstrap and Semantic-UI

Related

CSS compatibility issues on IE 8

We are working on redesigning our web-based application’s Front-end. We started with a PoC based on Extjs 6 and we are facing few compatibility issues.
These compatibility issues are related to IE8 and CSS, while it is mentioned on your website that Extjs6 is fully compliant with IE8.
CSS classes work perfectly with all Major Web Browsers (Firefox, IE11, Chrome...) but some do not on IE8.
This is an example of CSS not working properly under IE8:
Ext.create('Ext.button.Button',{
text:'Button Test',
cls: 'btnColor',
renderTo: Ext.getBody(),
});
.btnColor {
background-color: green;
border-color:green;
}
Works on IE11 :
But not on IE8 :
We would like to know if this is a known issue and is there a specific processing which allows us to handle this kind of needs.
Thank you in advance.
The element in your comment above is the wrong element - that's the inner element for the button; you want the class with an id something like button-1009 (it's going to be an anchor or div tag a few elements up in the hierarchy).
And as to why it's not working - there are going to be multiple CSS selectors that define the background colour. The default one, from ExtJS, is going to be x-btn-default-large. The full CSS class for the attribute is going to be something like x-btn buttonCls x-unselectable x-btn-default-large x-border-box.
Done like that, both the buttonCls and x-btn-default-large are equally valid choices - the browser must pick one to use. IE8 is picking the last one; other browsers are picking the first one. Neither is wrong - the ambiguity is in your code.
To fix it, make your CSS selector more specific. Try:
.x-btn.buttonCls {
background-color: green;
border-color:green;
}
This applies to buttons (which will be the only things that have the x-btn componentCls attribute) that have the buttonCls cls attribute.
The problem is JavaScript syntax.
IE8 and earlier are strict about trailing commas on arrays and objects.
Your line renderTo: Ext.getBody(), ends in a comma, but is the last item in the object. In IE8, this will fail to compile.
The solution is simply to remove that comma.
You can keep an eye open for theses kinds of things by running your code through a linting tool like JSHint or ESLint, which will flag this kind if thing up.
The answer of Sencha support team:
https://www.sencha.com/forum/showthread.php?305980-CSS-compatibility-issues-on-IE-8.&p=1118734#post1118734
This clarified a lot for me, it might help you :)

CSS Specificity Filter

This is a long shot, but is there a tool available that optimizes CSS selectors by removing unneeded specificity?
I find that when I write CSS, I deliberately make my selectors more specific than necessary to avoid conflicts and for quasi-documentation.
It would be great if there were a tool that could analyze a given group of rules, determine their "uniqueness" in terms of overlap with other rules, and then strip away any unnecessary specificity.
I can't even begin to imagine how a tool developer would approach all of the scenarios this would require, but I've been blown away by others' ingenuities in this area before and figured it was worth asking.
Update:
I've added a bounty to this question, and the more I think about it, the more I realize how valuable a CSS Specificity Filter would be.
For example, when working with Nested Rules/Selectors in Sass and LESS, excessive nesting is a common and well-known antipattern that can easily lead to overly specific selectors.
There's a good illustration of this in the excellent TutsPlus course Maintainable CSS with Sass and Compass:
body {
div.container {
p {
a {
color: purple;
}
}
}
}
Sass will follow these nesting instructions and produce the following CSS output, raising no objection to any unneeded specificity:
body div.container p a {
color: purple;
}
If a Specificity Filter did/does exist, however, it would create potential benefits for CSS developers:
You could organize your stylesheets as a 1:1 mapping of the DOM, similar to what you see when you examine style rules in Firebug and Chrome Dev Tools. A smart editor/IDE could auto-populate styles for DOM elements with shared styles/classes. That redundancy would then, of course, be filtered out by the Specificity Filter/Optimizer.
Stylesheets could have their structure pre-populated by a tool that scans the DOM and translates it to CSS selectors/rules. This means a developer would only need to update the HTML; the CSS "tree" would be kept in sync to reflect the current state of the DOM. A smart editor would let you jump to the CSS definition for an element/class for styling -- or even make its style rules visible in a separate panel.
In a way, this almost seems like a step backward - like a feature you'd find in Dreamweaver or WebAssist to help newbs learn CSS. But the basic idea of a CSS selector optimization tool seems like a no brainer, and the type of workflow automation I've described would be the logical next step -- and the catalyst would be the Specificity Filter.
I looked into some of the better-known CSS editors and web IDEs, but haven't found anything offering this type of functionality beyond targeting a single element and generating a selector for it.
Update 2: CSS Selector Performance
In response to Spliff's comment, here are two great articles on CSS selector performance:
Performance Impact of CSS Selectors by Steve Souders
Efficiently Rendering CSS by Chris Coyier
Both agree that micro-optimizing CSS isn't worth the effort, but that over-qualified descendant selectors are "an efficiency disaster." I haven't benchmarked yet myself, but suspect that the kind of "DOM Mapping" approach I'm suggesting would cause a performance hit without an optimization step, either manual or automated.
Related Questions, Links, and Tools:
Points in CSS Specificity
Tool to See CSS Specificity
Tool for Cleaning Up CSS
Order by CSS Specificity
Top 5 Mistakes of Massive CSS
Google: Efficient CSS Selectors
Procssor
Clean CSS
CSS Tidy
You could attempt to take a different approach, try to write your selectors as small (low specificity) as possible. and only make them more specific when needed.
With that way of working you don't need a tool.
Just going to throw this out there-- it doesn't 'answer' your question,but it's a tool I like to spread the word about for people who do a lot of css programming: Firebug.
If you're not familiar with it, it's a tool for web browsers. You pull up your page once it's installed, right click and select 'Inspect Element.' It will show you all css affecting different elements on your page, and is useful for creating clean, precise css code. Also it makes it easier to see instant updates on what your page would look like with slight modifications. It will inform you of useless css code that's being overridden by other css code.
ALSO! Firebug now is available for almost all browsers. Not just Firefox. Personally, I'm partial to using it in Chrome.
We really can't do without specificity because it is the only thing that saves you when you have two or more rules colliding. Specificity brings sanity to the whole jumbled CSS rule, so it is more of a blessing than curse. Some of the stuff you talked about, like the CSS selector, can be done using Firefox/Firebug. I'm more disturbed by browser compatibility.
Actually there's a way you can do this using HTML5 and CSS3. The standard technique is to specify elements using the HTML 5 attribute "data-" and then do CSS selection for this attribute. This isn't the purpose of the attributes, but you can customly specify some elements that you can use to even switch the theme of a site.
So, for example, you can end up creating your specificity filters manually in CSS, by specifying
<b data-specificity=2>test</b>
where data-specificity only matches to parents above.
UPDATE:
Alright, so for example, let's say you have a paragraph class, but you want to specify which parent, or how many parents the paragraph can inherit properties from. You would use rules for each potential parent that can be inherited from:
p[data-specificity="1"]{
color:red;
font-family:verdana;
text-decoration:underline;
}
p[data-specificity="2"]{
color:black;
font-family:arial;
}
div.container > *[data-specificity="2"] {
font-family:impact;
color:blue;
text-decoration:underline;
}
So these rules mean that any p tag which is a direct child of the div container and has specificity 2, is allowed to inherit properties from the div container. The blue color of the div gets inherited by the p with data-specificity 2.
Here's a JSFiddle where you can see this!
The idea is that like this, using HTML5, you can control exactly which elements are allowed to inherit which properties. It's a lot of extra code to write (for both child and parent elements) but you can use this to get rid of some unnecessary specificity
I've never actually seen anyone use this method in practice, I pretty much just cooked it up for you, but I think it could be very useful, what do you think ?

Is there a CSS3 Reset?

I am simply wondering if there exists a global CSS reset for CSS3. Something along the lines of the commonly-used versions created by Eric Meyer or YUI, but for CSS3 specifically. I've queried channels such as Google, Github and here on SO, but haven't come across a comprehensive solution.
Edit:
The term "reset" is probably misleading since it deals mainly with resetting browser default settings. "Recalibration" may be better suited.
I should clarify and put forth a use case.
This would work in tandem with the normal CSS reset yet also handle any styling caused by rotation, box shadow, animation, border radius, etc. For example, as mentioned before on this post:
-webkit-transform:none; /* Safari and Chrome */
-moz-transform:none; /* Firefox */
-ms-transform:none; /* IE 9 */
-o-transform:none; /* Opera */
transform:none;
The above snippet, and others like it, would be associated with any HTML tags that might get affected by them, as it is with current CSS resets.
The implementation need for this would probably not be too common if you are in control of your properties. However if you are, for example, creating an app or plug-in that will be used across different domains, where the styling of the pages the plug-in script is invoked on can influence that of the plug-in itself, then something like this would be very useful.
I realize there are other ways to tame CSS inheritance and handle cross-domain issues, but this question is put forth regarding the CSS3 reset directly.
Much thanks.
The real way to solve your problem is either to use the scoped attribute, or to create your widget using the Shadow DOM.
This way, you can insulate yourself from external CSS. Unfortunately, neither are really ready for use, so yes, you'll have to manually protect yourself.
The alternative is to set everything (transform, font-size, padding, etc) in your code with !important, rather than resetting it to 0/none, then setting it anew.

What is the correct usage of CSS attr function?

Since this function is implemented in IE8, I wanted to see exactly what I could do with it, but I'm having trouble getting it to work anywhere other than the :before and :after css pseudo-elements. Should the following be allowed?
span[color] { color: attr(color); }
I tried it in Google Chrome too, but it didn't work. Also, what about more dynamic things like:
input[value=attr(default)] { color: gray; }
In CSS 2.1 (which is what should be used these days) the attr function is a little limited in what it can do. The only place where it can appear is in a content property on :before and :after pseudo-elements. So its sole purpose is generated content.
In CSS 3 this changed a bit, in that attr() may return other types than only strings and it can be used for other properties as well.
But bear in mind that most of CSS 3 is still a Working Draft with very few features (not including Values and Units) being a Candidate Recommendation. Support by User Agents for CSS 3 features varies currently between limited and next to non-existent. Mostly browser vendors seem to fight boredom by implementing "cool stuff" like rounded borders, text shadow, etc. which doesn't mean much work supporting it. But what you were looking at here is definitely beyond that and the WD status won't change in the near future. So don't expect it to be implemented anywhere.
Just use
span.red {}
for any different color, i don't think you need all combinations :)
Or just use
span[color="red"] {}

Acceptable CSS hacks/fixes

Is there a list of 'good' clean CSS hacks, which are certain to be future-proof?
For example, zoom:1 is safe, as long as it's only served to IE, and you remember it's there. The very common hack of using child selectors is not safe because IE7 supports them. Using height:1% just feels dirty (but that might just be me).
I know of ie7-js, so IE6 bugs don't worry me much. Also, I'm not looking for a religious debate, just sources.
Thanks for the replies - I've selected the one with best sources as answer.
Thanks also for the suggestions to use separate CSS files, or not to worry about it. I entirely agree with you, and for me, those are givens. But when faced with a layout problem, I want a safe fix that will minimise the risk that I'll have to revisit the problem in $IE or $FF + 1. Sorry I didn't make that clearer.
For the majority of IE bugs I think you're best off using conditional comments around a link to a browser specific stylesheet. It tends to keep things pretty neat and it's quite self documenting.
This is a good place for well-documented and well-tested browser bugs and the hacks allow you to work around them:
http://www.positioniseverything.net/
I've used Peter-Paul Koch's "QuirksMode" website a lot for issues involving CSS and cross-browser compatibility. He tends to frown on browser-specific methods, but he does have a page on CSS Hacks.
Nicole Sullivan (AKA Stubbornella) who works for the Yahoo Performance team suggested in The 7 Habits for Exceptional Perf that you should use the CSS underscore hack to patch up IE6 bugs because:
Hacks should be few and far between.
If you will only have 5-6 hacks (which is already plenty) then it would not make sense placing those in an external file and thereby separating it from its context.
An extra file would lead to performance penalties (Yahoo Best Practices, Rule 1).
It should however be noted that this is not valid CSS.
There's no such thing as a good clean/acceptable [css] hack - always code to Standards, and then use browser+version specific stylesheets for any hacks required to make things work.
For example:
default.css
default.ie6-fix.css
default.ie7-fix.css
default.ff2-fix.css
etc
Then, when new version of a browser are released, copy the previous version's hacks and remove the bits that no longer apply (and add new bits, if necessary).
(Load individual stylesheets using Conditional Comments for IE, and user-agent sniffing for other browsers.)
Underscore-hack for IE6-stuff works quite well, eg.
min-height:50px;
_height:50px;
It doesn't require moving things out of context into new css-files, only IE6 gets them and they're easy to filter out if you should decide to stop supporting IE6. They're also very minimal and won't clutter your CSS that much.
Modifying your CSS for browser-specific support is never wrong - as long as you can easily contain it. As you'll notice, standards-compliant browsers, * cough * everything except MSIE, will never break with future releases. New W3C standards also don't break previous standards, they usually deprecate or extend previous standards at the most.
People have mentioned conditional comments which are great for handling IE. But you'll need a bit more for handling all browsers (mobile, gecko, webkit, opera, etc.). Usually you'll parse the incoming request headers to fetch the browser type and version from the User-Agent param. Based on that you can begin loading your CSS files.
I belive the way most of us do it is by:
First developing for one standards-compliant browser (let's take FF for example)
Once the CSS is complete you approach providig support for IE (this can be easily done with the conditional comments, as perviously mentioned)
First create a CSS file that will fine tune everything for IE6 and any other version below
Then create a CSS file that will handle everything for IE7
Lastly, create a CSS file that will handle everything for IE versions of IE8 and greater
Once IE9 comes out, make sure you set IE8+ handling to IE8 specific, and create a IE9+ CSS file with required fixes
Finally, create an additional CSS file for webkit fixes
If required, you can also create additional files to specifically target Chrome or Safari if required
Concerning browser specific CSS implementations, I usually group all of those in my main css file (you can easily do a search for those and replace them in one document if needed). So if something has to be transparent, I'd set both opacity and filters (MSIE) in the same block. Browsers just ignore implementations they don't support, so your safe. Specific implementations I'd tend to avoid are custom implementations (hey, I like the -moz box above the W3C one, but I just don't want to rely on it).
As it goes with CSS inheritance and overriding, you don't have to redefine all the CSS declarations and definitions in every CSS file. Each consecutively loaded CSS file should only contain the selector and specific definitions required for the fix, and nothing else.
What you end up with in the end is your (huge) main css file and others, containing a few lines each, for specific browser fixes - which sums up to something that's not that very hard to maintain and keep track of. It's a personal preference what browser your base css file will be based off, but usually you'll be targeting a browser that will create the least amount of issues for other browsers (so yes, developing for IE6 would be a very poor decision at that point).
As always, following good practices and being pragmatic and meticulous with selectors and specifics about each class and using frameworks will lead you down the path of goodness with seldom fixes required. Structuring your CSS files is a huge plus unless you want to end up with an unordered meaningless mess.
Centricle has a good list of CSS hacks and their compatibilities.
I don't think you'll find a list of hacks that will be future proof, as know one can tell what stupid thing will be implemented in IE next.
This article is a good summary of CSS hacks: http://www.webdevout.net/css-hacks
Here's a good list of filters that are very stable:
/* Opera */
.dude:read-only { color: green; }
/* IE6/IE7 */
#media,
{
.dude { color: silver;}
}
/* IE8 \0 */
#media all\0
{
.dude { color: brown; }
}
/* IE9 monochrome and \9 */
#media all and (monochrome: 0)
{
.dude { color: pink\9; }
}
/* Webkit */
* > /**/ .dude, x:-webkit-any-link { color:red; }
/*
* > /**/
/* hides from IE7; remove if unneeded */
/* Firefox */
#-moz-document url-prefix()
{
.dude { color: green; }
}
When defining rules, I find it good to allow natural degradation take place, for instance, in CSS3 there is support for RGBA Colour models, but there isn't in CSS2, so I find myself doing:
background-color: #FF0000;
background-color: rgba( 255,0,0, 50% );
So that when the later rule fails on older browsers which don't support it, it will degrade to the previously defined style.
I prefer the global conditional comment technique described by Hiroki Chalfant;
I find it helpful to keep my IE-targeted rules side-by-side with my standards-targeted rules in a single valid stylesheet.

Resources