tl;dr = "Anyone know how to apply chained classes for IE6 using jQuery or similar?"
Right,
perhaps I ask the impossible? I consider myself fairly new to Javscript and jQuery, but that being said, I have written some fairly complex code recently so I am definitely getting there... however I am now possed with a rather interesting issue at my current freelance contract.
The previous web coder has taken a Grid-960 approach to the HTML and as a result has used chained classes to style many of the elements. The example below is typical of what can be found in the code:
<div class='blocks four-col-1 orange highlight'>Some content</div>
And in the css there will be different declarations for: (not actual css... but close enough)
.blocks {margin-right:10px;}
.orange {background-image:url(someimage.jpg);}
.highlight {font-weight:bold;}
.four-col-1 {width:300px;}
and to make matters worse... this is in the CSS:
.blocks.orange.highlight {background-colour:#dd00ff;}
Anyone not familiar with this particular bug can read more on it here: http://www.ryanbrill.com/archives/multiple-classes-in-ie/ it is very real and very annoying.
Without wanting to go into the merrits of not chaining classes (I told them this, but it is no longer feasible to change their approach... 100 hand coded pages into a 150 page website, no CMS... sigh) and without the luxury of being able to change the way these blocks are styled... can anyone advise me on the complexity and benefits between any of my below proposed approaches or possible other options that would adequately solve this problem.
Potential Solution 1
Using conditional comments I am considering loading a jquery script only for IE6 that:
Reads the class of all divs in a certain section of the page and pushes to an array
creates empty boxes off screen with only one of the classes applied at a time
Reads the applied CSS values for each box
Re-applies these styles to the individual box, somehow bearing in mind the order in which they are called and overwriting conflicting instructions as required
Potential Solution 2
read the class of all divs in a certain section of the page and push to an array
Scan the document for links to style sheets
Ajax grab the stylesheets and traverse looking for matching names to those in class array
Apply styles as needed
Potential Solution 3
Create an IE6 only stylesheet containing the exact style to be applied as a unique name (ie: class='blocks orange highlight' becomes class='blocks-orange-highlight')
Traverse the document in IE6 and convert all spaces in class declarations to hyphens and reapply classes based on new style name
Summary:
Solution 1 allows the people at this company to apply any styles in the future and the script will adjust as needed. However it does not allow for the chained style to be added, only the individual style... it is also processor intensive and time consuming, but also the most likely to be converted into a plugin that could be used the world over
Solution 2 is a potential nightmare to code. But again will allow for an endless number of updates without breaking
Solution 3 will require someone at the companty to hardcode the new styles every time they make a change, and if they don't, IE6 will break.
Ironically the site, whilst needing to conform to IE6 in a limited manner, does not need to run wihtout javascript (they've made the call... have JS or go away), so consider all jQuery and JS solutions to be 'game on'.
Did I mention how much i hate IE6?
Anyway... any thoughts or comments would be appreciated.
I will continue to develop my own solution and if I discover one that can be turned into a jQuery plugin I will post it here in the comments.
Regards,
Mike.
edit: added tl;dr to the top.
Here's a combination solution: http://code.google.com/p/ie7-js/
Fixes the multiple class bug and some other selector issues you may encounter.
I believe that if you look closely at how IE6 handles class chaining, and if the order of the class names are consistent, then you can avoid some of the IE6 issues with careful class coding.
First have a look at your provided HTML example:
<div class='blocks four-col-1 orange highlight'>Some content</div>
IE6 will apply the CSS in the order of the class names, starting with 'blocks' and continue through to 'highlight'.
Now look at your initial group of classes:
.blocks {margin-right:10px;}
.orange {background-image:url(someimage.jpg);}
.highlight {font-weight:bold;}
.four-col-1 {width:300px;}
These would be applied without any problems as each applies different properties. However, if you should, say, apply a different background with 'highlight' you should see that it will override the one set with 'orange'.
Using this same logic approach, let's have a look at the last class you defined:
.blocks.orange.highlight {background-colour:#dd00ff;}
This class should only apply to objects that have all three class names applied. What happens in IE6 is the first two class names are ignored and only the last class name is used to apply the styling. This means that any object that has the class 'highlight' will receive the new background property. (PS: the CSS property should be background-color, no 'u')
However, if you use other selector methods you can possibly avoid the limitations by applying nested ids/classes [#section .blocks] and/or object associations [form input.highlight]. This complicates the process I know, but at some point we simply need to stop trying to fully support out dated software.
Note: IE6 has not received any updates for two years and the browser itself is nine years old. The browser has two successors and a third is already in development. There should be some cutoff where an acceptable loss of presentation is allowed.
OK... as there is some confusion about what I am asking:
I have been called in to work on a project that is almost completed.
There are no templates.
There are 100+ pages, hand coded and a looming deadline. Here is some actual code from the HTML/CSS all written by the last guy (not abreviated like above):
<div class="block four-col-1 gold black-bg">
<h1>Self Managed Super</h1>
<a class="highlight" href="#"><span class="left bottom">
<strong><span class="text-white">Bolster your<br />
portfolio</span><br /></strong>
with unique<br />
investment<br />
options</span>
<img src="/AU/individuals/_images/superannuation-2.png" alt="" /></a>
</div>
<div class="block four-col-1 grey-light black-bg">
<h1>Self Managed Super</h1>
<a class="highlight" href="#"><span class="left bottom">
<strong><span class="text-white">Financial <br />
flexibility,</span></strong> <br />
into and <br />
throughout <br />
retirement
</span>
<img src="/AU/individuals/_images/superannuation-3.png" alt="" /></a>
</div>
and here is some of the relevant CSS:
.block .highlight {display:block;position:relative;height:auto;min-height:110px;-webkit-border-radius: 4px;-moz-border-radius: 4px;border-radius: 4px;}
.block .highlight:hover {border:1px solid #ddd;}
.block .bottom {position:absolute;font-size:11px;line-height:12px; bottom:10px;letter-spacing:-0.2px; }
.block .left {float:left;font-size:11px;margin-left:8px;width:75%;}
.block.black-bg p, .block.black-bg p * {color:#828282;}
.block.black-bg p * span.text-white {color:#fff;}
.block img {position:absolute;bottom:0;right:1px;z-index:0}
.block .highlight img {position:absolute;bottom:0;right:0px;z-index:0}
.highlight:hover {opacity: .75; filter: alpha(opacity=75); -ms-filter: "alpha(opacity=75)";-khtml-opacity: .75;-moz-opacity: .75; overflow:visible;}
.content .block.black-light.highlight, .block.black-light .highlight, .block.black-light
.block-inner {background:url(/AU/_images/system/block-black-light.gif) no-repeat top left;}
.content .block.grey-light.highlight, .block.grey-light .highlight, .block.grey-light
.block-inner {background:url(/AU/_images/system/block-grey-light.gif) no-repeat top left;}
.content .block.orange.highlight, .block.orange .highlight, .block.orange .block-inner {background:url(/AU/_images/system/block-orange.gif) no-repeat top left;}
.content .block.gold.highlight, .block.gold .highlight, .block.gold .block-inner {background:url(/AU/_images/system/block-gold.gif) no-repeat top left;}
.content .block.blue-light.highlight, .block.blue-light .highlight, .block.blue-light .block-inner {background:url(/AU/_images/system/block-blue-light.gif) no-repeat top left;}
.content .block.blue-dark.highlight, .block.blue-dark .highlight, .block.blue-dark .block-inner {background:url(/AU/_images/system/block-blue-dark.gif) no-repeat top left;}
.content .block.black-light.black-bg.highlight, .block.black-light.black-bg .highlight, .block.black-light.black-bg .block-inner {background:url(/AU/_images/system/black-block-black-light.gif) no-repeat top left;}
.content .block.grey-light.black-bg.highlight, .block.grey-light.black-bg .highlight, .block.grey-light.black-bg .block-inner {background:url(/AU/_images/system/black-block-grey-light.gif) no-repeat top left;}
.content .block.orange.black-bg.highlight.block.orange.black-bg .highlight, .block.orange.black-bg .block-inner {background:url(/AU/_images/system/black-block-orange.gif) no-repeat top left;}
.content .block.gold.black-bg.highlight, .block.gold.black-bg .highlight, .block.gold.black-bg .block-inner {background:url(/AU/_images/system/black-block-gold.gif) no-repeat top left;}
.content .block.blue-light.black-bg.highlight, .block.blue-light.black-bg .highlight, .block.blue-light.black-bg .block-inner {background:url(/AU/_images/system/black-block-blue-light.gif) no-repeat top left;}
.content .block.blue-dark.black-bg.highlight, .block.blue-dark.black-bg .highlight, .block.blue-dark.black-bg .block-inner {background:url(/AU/_images/system/black-block-blue-dark.gif) no-repeat top left;}
(Code is essentially exactly as he wrote it, in all it's unformatted, hideous beauty.)
If you can be bothered to read all that (and most of you probably can't - hence my abbreviations above) you would see that whilst some classes are unique and do not conflict, some do. The result is that some blocks which are expected to be balck, in EI6 are blue, and the margins in EI6 are often wrong, and the absolutely positioned images also break particularly when combined with an IE PNGFix to make them appear transparent as expected.
Also, due to the nature of the deadlines, assume that going over each and every of the 100+ pages and editing the HTML is no longer an option. This was my recommendation from day one and whislt the client accepts that what they have is well and truly less than ideal, they are also working to a tight deadline.
This leaves only two options for edits. Change the CSS so it works across all browsers (as this is called on each page), or generate some Javascript (again, this can be called onto each page using an include) to do something with the HTML on every page on the site, or something else tricky. Changing code in the included pages is easy, changing the HTML in each of the blocks in question is out.
I completely understand what everyone is commenting on so far and thanks for those... they were my initial solutions in both cases, and I wouldn't be on here if they were an option.
Thanks to everyone who has read this, but I really am trying to find some super tricky solution to the entire problem of non-chaining classes in IE6. potentially for broader use than this project. However I now only have 5 working days to find the answer before my contract ends, so if we don't we will just hack an IE6 style sheet that makes all the blocks appear in one way on that browser and leave it at that. I would prefer to find a universal solution, but... meh. Hopefully 18 months from now the user base of IE6 will be so low that it's no longer an issue.
Thanks everyone.
Cheers,
Mike.
I think you may have missed the point of my earlier comment. I was not confused about your request but was trying to explain how you might approach the task should the coding of the site be consistent.
For a more detailed example, lets take a line from your last CSS example, minus the actual styling properties:
.content .block.orange.highlight, .block.orange .highlight, .block.orange .block-inner { }
Following the behavior of Internet Explorer 6 in regards to chained CSS classes, that line of code would be seen by IE6 as:
.content .highlight, .orange .highlight, .orange .block-inner { }
Notice that the chained class names are ignored for all except the last name in the chain. Since you had already rejected the JavaScript solutions that were proposed by others, the only solution I can see is to design your CSS class definitions with this IE6 limitation in mind as you code.
This does not make the task simple as the whole reason for chaining the classes is to be able to apply special conditional styling without increasing the DOM nodes of the document. However, in order to continue to support enhanced feature programming in IE6, without the help of some JavaScript solutions, you will simply have to put in more effort to find older conventional methods for the same result. I know this comment is likely a bit late for your project but I hope it helps with the planning process when dealing with IE6 styling.
Related
I'd like to give broken/errored images some extra CSS:
img:error {
max-width: 20px;
max-height: 20px;
}
but that doesn't work. Is there a way with pure CSS to do this? Is there an img pseudo selector for this? Or even better: a dirty hack that works?
I've looked around, but nobody seems to be wondering =)
(Yes, I know JS can do it and I know how; no need to mention it.)
There is no way in CSS specs or drafts, but Firefox has a proprietary selector (pseudo-class) :-moz-broken. Its documentation is very concise and it says “intended for use mainly by theme developers”, but it can be used e.g. as follows:
:-moz-broken { outline: solid red }
:-moz-broken:after { content: " (broken image)" }
Although the documentation says that it “matches elements representing broken image links”, it actually matches broken images (an img element where the src attribute does not refer to an image), whether they are links or not. Presumably, “links” really means “references” here.
CSS 2.1 says: “This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification.” But Selectors Level 3 (CSS3 Selectors) just says about them: “They are explained in CSS 2.1.” In practice, browsers handle them differently. Oddly enough, Firefox supports :-moz-broken:after but ignores :-moz-broken:before. It does not support either of these pseudo-elements for normal images, but img:after, too, is supported for a broken image (i.e., the specified content appears after the alt attribute value).
For this, you should use the alt attribute, wich shows up if link is broken and you can as well style background of image :
example:
img {
display:inline-block;
vertical-align:top;
min-height:50px;
min-width:300px;
line-height:50px;
text-align:center;
background:
linear-gradient(to bottom,
blue,
orange,
green);
font-size:2em;
box-shadow:inset 0 0 0 3px;
}
These style will be hidden when image is shown.
http://codepen.io/anon/pen/Kxipq
As you can see, we do not check for broken links, but offer alternative , usefull for blind people , searchengines, whatever , and some extra styles finishes it :)
some extra Image alt attribute best practices
<img src="not_found_image.png" onerror='this.style.display = "none"' />
from:
https://www.geeksforgeeks.org/how-to-hide-image-not-found-icon-when-source-image-is-not-found/
NO there is no :error pseudo class. This is a good site for a comprehensive list of what is available:
http://reference.sitepoint.com/css/css3psuedoclasses
July, 2015 EDIT/ADDITION:
(Thank you Rudie)
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
No. There is nothing in CSS selectors level 2.1 or level 3 that allows targeting an image like that.
This is close:
<style>
img[data-broken="true"] {
visibility: hidden;
}
</style>
<img src="none.webp" onerror="this.setAttribute('data-broken', 'true')">
Strictly speaking, it sill uses JavaScript. But the JS is self contained in the image HTML code.
Lately I wondered about editing elements styles not by switching their classes on dom, but by changing the actual ruleset for the css class or selector.
So instead of something like
$('.some').hide()
or
$('.some').addClass('hidden')
Why not alter a rule directly with document.styleSheets and stuff?
Wouldn't this approach be generally more performant, at least with many elements, as we'd let the browser handle the ruleset changes natively?
You could for example add an style to .some, like display: none; and all .some elements would be immedeatly be hidden. There is no need to iterate over all those elements in js and hide them manually(like the example above).
Changing rulesets directly would more likely encourage classes that are context aware(or however you would call this..), as you'd hide all #persons > .item or something.
I still don't know best practices regarding classes that are named with context in mind, like for example control names like .calendar .ticket .item, versus single functionality classes like .hidden .left .green, as I usually need both types of conventions.
I am just asking what you think about this and what are benefits and drawbacks of the modifiying stylesheet approach versus how libraries like jquery handle changing styles?
Also, what do you think is good practice, what do you regard more as a hack?
cough javascript and hacking cough
Manipulating document.styleSheets is tricky due to differing implementations and the lack of a rule selector API. Currently if you want to manipulate a rule in a stylesheet you have to go through this process:
iterate over document.styleSheets
iterate over rules within current styleSheet object
if rule matches our class, edit the rule styles
Then there's the cascading issue. How do you know that a particular style on the rule you've matched won't be overridden by a different rule somewhere in the pages stylesheets? If you just bail out after changing the first matching rule you find, you can't be sure that the styles you set will actually be applied to the element, unless you stick an !important on each one, which will leave you with a whole different set of problems.
Even when you've manipulated the style sheet rules, the browser still has the same job to do — it has to recalculate all the styles by applying the cascade.
So, manipulating styleSheets doesn't look too appealing now, does it? Stick to class switching, trust me. Using jQuery and modern APIs like querySelectorAll make it plenty fast and the browser still does all the hard work like recomputing the style values.
Such a tricky question :(
But if you take boilerplate for instance, it has a some standard classes to use like:
/* Hide from both screenreaders and browsers: h5bp.com/u */
.hidden { display: none !important; visibility: hidden; }
/* Hide only visually, but have it available for screenreaders: h5bp.com/v */
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: ; position: absolute; width: 1px; }
/* Hide visually and from screenreaders, but maintain layout */
.invisible { visibility: hidden; }
Where it gets tricky is, IF it is something you need to hide because of JS, then you should ONLY hide it with JS. Then it will function if JS is disabled.
If it is something that is not JS dependent, then you hide it in the HTML.
So JS function = hide with JS (either by using JS or adding hide classes)
Basic HTML hide = hide with HTML class
Styleswitching vs JS switching
Basicly JS switching gives you the oppertunity to add effect etc, just using predefined classes limits that somewhat. But would love to see some ressource comparisons :)
Seen this done before, am curious as to how it is done. Example can be found over at http://wordographic.info/
For example, if I tag a post blue, the bg-color of the post turns blue, etc.
Anyone know how this is done?
Thanks.
Found a way to do this with only HTML/CSS. Pretty simple, just add the {Tag} block to any div class wrapping the post area but make sure it's between {block:Posts} and {block:Text} etc. Now whatever you tag a post now becomes a new class.
{block:Posts}
{block:Text}
<div class="post {block:HasTags}{block:Tags}{Tag} {/block:Tags}{/block:HasTags}">
{block:Title}<h2>{Title}</h2>{/block:Title}
<p>{Body}</p>
</div>
{/block:Text}
{/block:Posts}
Pay attention to the third line down. it is important to add a space after {Tag} otherwise they won't be seperated in the HTML.
The CSS would look like this:
.post { /* default style */
background: #ccc;
float: left;
margin: 10px;
position: relative;
}
.blue { /* when tagged blue, use this style */
background: blue !important;
}
Works! Pretty simple, no jquery required!
Thanks Blender, wouldn't have thought of this for some reason if I didn't read your jquery method :)
With jQuery, anything's possible! This isn't going to work right away, so tweak it for your theme:
$('.post-class .tag-container .tag').each(function() {
$(this).closest('.post-class').addClass($(this).text());
});
It is nothing to do with JS, such things are done on server-side. Depends on tags some properties are set to posts and then they are taken into consideration while rendering them to HTML.
You want to get the post's tags as class names so you can style posts with CSS, and there is a variable you can use for this purpose. In your template simply use {TagsAsClasses}. This will render HTML friendly class names.
An HTML class-attribute friendly list of the post's tags.
Example: "humor office new_york_city"
For detailed explanation see Post chapter in Tumblr docs.
I am trying to get leading and kerning to work on some sIFR 3 type on a site I'm working on (as described in the wiki: http://wiki.novemberborn.net/sifr3/Styling), but these two parameters seem to have no effect no matter what I do.
I am not using intergers (no 'px' or 'em') just as it requires. I've also tried several different font swf files, just to make sure it's not the font. I don't know why it doesn't work. All of the other css parameters that I assign to .sIFR-root work just fine. Here's a sample of my code using 'leading'.
In sifr_config.js:
sIFR.replace(snl, {
selector: '.section-title h1',
css: ['.sIFR-root { color: #FFFFFF; text-align: center; leading:2; }'],
wmode: 'transparent'
});
In the HTML doc:
<div class="section-title">
<h1>sIFR Text</h1>
</div>
(I've also tried the css code with and without the square brackets, as I've seen it done both ways. Doesn't seem to make a difference).
What am I doing wrong? Any help would be greatly appreciated; thanks!
ETA: Found an less hackish way:
line-height seems to work when added to the CSS for the replaced element (in my example that'd be: .sIFR-active .section-title h1). So I was able to use regular old line-height to fake a margin.
All righty—since this one left everyone speechless, here's what I discovered:
Originally, there were many suggestions for using leading as a replacment for margin-top or padding-top since these will not work with sIFR. This is what I was trying to use it for. I had a single line of text and needed to give it some space up top, so I was trying to do this by increasing the leading (line height) to no avail. I think this worked at one point, but then as I was looking at the change logs for all the revisions of sIFR, I found a note about a "fix" to leading. Apparently the developer considered leading being recognized on single-line text as a bug, so "fixed" it so that leading is only applied when the text is multiple lines. I tested by putting a line-break before my text, and sure enough, leading started to work!
So it seems that now, in order to achieve a top margin on my sIFR header, I have to add unneccessary code one way or another—by wrapping it in a div or span with a top margin, or by adding a line break and using negative leading.
I still have no idea about the kerning, but letter-spacing seems to be working, so…
If anyone has any additional insight to offer, I'm all ears!
Here's what works for me, using sIFR 3 to get a h2 with Serifa font in red with minimal letter spacing and leading. The actual sIFR swf is nothing special, simply created as per the sIFR documentation. As mentioned above, offsetTop and tuneHeight also work for adjusting positioning (shown below although I haven't used them so set to 0).
In sifr.css
.sIFR-active h2.replace {
color: #FF0000;
visibility: hidden;
font-family: arial,helvetica,clean,sans-serif;
font-size: 2.5em;
text-transform:uppercase;
}
in sifr-config.js
sIFR.replace(serifa, {
selector: 'h2.replace',
css: ['.sIFR-root { letter-spacing: -2; leading: -15; kerning:true; color:#FF0000; text-transform:uppercase; font-size:2.5em; }' ],
tuneWidth: '0' , tuneHeight: '0' , offsetTop: '0' });
In html page (for example):
<div class="column grid_4">
<h2 class="replace">Title here</h2>
</div>
This demo, which goes along with this article, succintly describes what I need to do. However I am not impressed by the use of javascript for something that should be possible in pure CSS.
The articles referenced (which I also found independently when looking for a way in CSS) don't perform the same function as the watchmaker demo - the 456 boxes demo doesn't slide under the other boxes when the screen width gets too small.
I've been playing about with the article code and trying various ideas in CSS, but nothing lays out correctly. Also I would prefer progressive enhancement over graceful degradation.
I realize this is an old question, but I wanted to bubble up the answer you should be using now: flexbox. The original demo from the question is long gone, but the markup was this (courtesy of the Wayback Machine):
<div id="one">I am 150px high</div>
<div id="two">I am 200px high</div>
<div id="three">I am 120px high</div>
<div id="four">I am 300px high</div>
In order to equalize the heights using flexbox, you would need to have a container wrapped around them:
<div class="container container--equal-children">
<!-- those four divs -->
</div>
Setting that to display: flex and setting align-items to "stretch" gives the desired effect:
.container--equal-children {
display: flex;
align-items: stretch;
}
Once that’s in place, you can skip the whole sizing thing and let the children flex to fill 1/4 the space:
.container--equal-children #one,
.container--equal-children #two,
.container--equal-children #three,
.container--equal-children #four {
flex: 0 1 25%;
}
They will all automatically be the same height.
I put together a CodePen that lets you toggle the flexbox rules on and off. It’s worth noting only the toggling functionality requires JS. There are also some "for presentation only" style rules I’ve added (which are noted) to demonstrate the design behavior.
Unfortunately, there really isn't a good way to do it in pure CSS. I assume that you want a dynamic height of containers based on a single parent container. Cross-browser issues make it an absolute nightmare, and the relatively small amount of JavaScript needed to accomplish the effect, IMO, is a better approach than trying to maintain really ugly and nasty CSS rules, having to import other CSS rules to fix things in certain browsers, etc, etc.
There's a reason these "equal heights" scripts even exist, and it's because of how much of a hassle the effect in pure CSS is.
I would stick with the JavaScript solution.
This is something which you'd think would be simple but is actually really tricky.
The "sliding under" aspect isn't really related to maintaining the same size. That's just how floating works. They probably have a rule like:
.box { float: left }
with markup like:
<div class="container">
<div class="box"></div>
<div class="box"></div>
</div>
If they gave .container a fixed width, that would prevent the .box's from sliding under each other.
If all you're looking for is to have background colors under various boxes of fixed width, there is an easy way to accomplish this without JS.
You can give .container a background image that has the backgrounds for all the boxes and tiles vertically. With your first example, it would be only a few pixels high with a 200 px section of orange, 200px of blue, 200px of red, and 200px of green.
Since if you "clear" the .container it grows to contain all the boxes, the background boxes would appear to all be the same height.
Anything more complicated such as vertically centering the text in the second example, and you're probably better off going with one of the JS scripts to even out the boxes.