Hiding inline SVG icons from screen readers

Icon fonts are finally being phased out in favour of a technology that’s more fit for purpose: SVG. There are many tutorials and guides that describe different ways in which you can use SVG icons, which is great. I do however see an issue related to accessibility pop up now and again, so I’d like to share a little tip about that. Many, probably the majority, of articles explaining how to use inline SVG for icons describe multiple ways of ensuring that your SVG graphics have a text alternative. That can be appropriate, but most of the time, at least in my experience, you just want an icon as an added visual cue alongside some text. Just like adding an image via the background-image CSS property. And icons of that kind should not have any text alternative since for a screen reader user that will just duplicate the information already available in plain text. If you use background-image to insert an SVG icon, there is no problem. Screen readers will treat the SVG like any other background image and ignore it. Likewise if you use an img element with an empty alt attribute (alt=""), the SVG will be ignored. The problem is related to using inline SVG, i.e. the svg element. SVG files may contain a title element which may or may not get announced by screen readers (depending on SVG embedding technique, browser name and version, and screen reader name and version). So far I haven’t run into a situation where I want any other behaviour than screen readers completely ignoring icons (since they are all accompanied by text). After a bit of testing, I found that simply adding aria-hidden="true" to the svg element solves the problem. So, this is the svg markup I use (haha) for icons contained in an SVG sprite file: <svg aria-hidden="true"> &Tab;<use xlink:href="icons.svg#icon" /> </svg> The end result to the user is essentially the same as this: <img src="icon.svg" alt="" /> But you get the benefits of being able to affect icons via CSS and having the icons all contained in a single file to reduce HTTP requests (which HTTP/2 will eventually make less relevant but for now it’s still relevant for many sites). Don’t want to use a sprite? Just replace the use element with the appropriate SVG code. Note that aria-hidden should only be used when you really want to hide the svg element completely from screen readers. If you use SVG to embed an image that is not just decorative, you need to make sure there is a text alternative. Check out Tips for Creating Accessible SVG and Accessible SVGs for more information on how to do that. Posted in SVG, Accessibility.Copyright © Roger Johansson

Posted on: 29 September 2016 | 5:00 pm

Linting CSS with stylelint

I like to keep my CSS tidy and consistently formatted. One of the tools I use to help with that is stylelint. If anyone’s curious, this post explains how I configure it. You can run stylelint in multiple ways. I use it via the PostCSS plugin, but you can run it from the command line, from within code editors like Atom and Sublime Text, or call it from Node scripts. There are different ways to specify the configuration, but I always use a .stylelintrc config file in the root of my projects. This is the configuration I use: "at-rule-empty-line-before": "always", "block-closing-brace-newline-after": "always", "block-closing-brace-newline-before": "always", "block-no-empty": true, "block-no-single-line": true, "block-opening-brace-newline-after": "always", "block-opening-brace-space-before": "always", "color-hex-case": "lower", "color-hex-length": "short", "color-no-invalid-hex": true, "color-named": "never", "comment-empty-line-before": "always", "comment-whitespace-inside": "always", "custom-property-no-outside-root": true, "declaration-bang-space-after": "never", "declaration-bang-space-before": "always", "declaration-block-no-shorthand-property-overrides": true, "declaration-block-semicolon-newline-after": "always", "declaration-block-semicolon-space-before": "never", "declaration-block-trailing-semicolon": "always", "declaration-colon-space-after": "never", "declaration-colon-space-before": "never", "function-calc-no-unspaced-operator": true, "function-comma-space-after": "always", "function-comma-space-before": "never", "function-parentheses-space-inside": "never", "function-url-quotes": "none", "indentation": "tab", "max-empty-lines": 3, "media-feature-colon-space-after": "never", "media-feature-colon-space-before": "never", "media-feature-no-missing-punctuation": true, "media-query-list-comma-newline-after": "never-multi-line", "media-query-list-comma-newline-before": "never-multi-line", "media-query-parentheses-space-inside": "never", "number-leading-zero": "always", "number-zero-length-no-unit": true, "rule-nested-empty-line-before": "never", "rule-non-nested-empty-line-before": "never", "selector-combinator-space-after": "always", "selector-combinator-space-before": "always", "selector-list-comma-newline-after": "always", "selector-list-comma-newline-before": "never-multi-line", "selector-list-comma-space-before": "never", "selector-pseudo-element-colon-notation": "double", "selector-type-case": "lower", "string-quotes": "double", "value-list-comma-space-after": "always", "value-list-comma-space-before": "never" So what does that make my CSS look like? First, here’s a snippet that stylelint will go mad about: .thing { padding: 24px 0; background: #EEE; color: #333333 } .thing:before { display: inline-block; background: url("icon.svg"); width: 24px; height: 24px; content:''; } .thing h2, .thing p {margin-top:12px;} .thing-thing { background-color: rgba(0,0,0,0.4); min-width:calc(50% - 100px)!important; } @media only screen and (min-width : 600px) { .thing { padding:48px 0; } } Here’s the same snippet cleaned up so that stylelint with the above configuration won’t complain: .thing { padding:24px 0; background:#eee; color:#333; } .thing::before { display:inline-block; background:url(icon.svg); width:24px; height:24px; content:""; } .thing h2, .thing p { margin-top:12px; } .thing-thing { background-color:rgba(0, 0, 0, 0.4); min-width:calc(50% - 100px) !important; } @media only screen and (min-width:600px) { .thing { padding:48px 0; } } Most likely this is not exactly how you prefer to format your CSS. For instance I know that many people use a space after the colon in declarations and some like to separate rules with an empty line. Luckily that is totally configurable with stylelint. I don’t really have to think about most of these rules while writing CSS since I use CSScomb to fix them automatically if I make a mistake. So I always have a Grunt watch task running that runs CSScomb before stylelint, which reduces the number of errors I have to fix manually. But since I write the changes CSScomb makes back to the source CSS I always see the linted CSS and it becomes second nature, as does the sort order enforced by CSScomb (more on that in a future post, I hope). There is also an ongoing discussion about adding autocorrect to stylelint, which could make CSScomb redundant if you use stylelint. Whether you agree with the rules I use or not, linting your CSS is a good idea. Find a stylelint implementation that fits into your workflow, configure rules to match your preferences and start linting. Posted in CSS.Copyright © Roger Johansson

Posted on: 2 April 2016 | 5:00 pm

Why I don’t use CSS preprocessors

Whenever I mention that I don’t use CSS preprocessors I tend to get strange looks from people who cannot imagine writing CSS without Sass. And so I have to defend my choice and explain why, over and over. Some people will understand, most won’t. Or they don’t want to. But here’s an attempt to explain my reasoning. Back when CSS preprocessors first came into fashion I did try using them. And then every couple of years, due to external pressure and nagging, I have taken new looks and given them new chances. But to me they’ve always felt like solutions in need of a problem to solve. That is, I don’t really find the “problems” with CSS that preprocessors are intended to solve, problems. The scale of the site I’m building does not matter, be it a tiny site with just a few static pages or a humongous corporate intranet. I simply have never felt the need for mixins, nesting or extends. A list of reasons then: I don’t feel the “problems” CSS preprocessors intend to solve are serious enough to warrant the cost, i.e. to me the solution is worse than the problem. I want absolute control of my CSS, which means I want to work hands on with it, and see exactly what will be sent to the browser (well, before it’s minified and gzipped, of course). If that means seeing the same declarations repeated in several rules, or having to see what vendor prefixes look like, so be it. To me, WET CSS is much more understandable and maintainable than DRY black box pseudo-CSS. I don’t want to learn and depend on a non-standard syntax to wrap my CSS in, making it require compilation before browsers can understand it. Neither do I want my colleagues to have to. I want my source CSS to be deployable at all times, albeit in un-minified, un-concatenated form. If my build process fails, for whatever reason (like an unpublished npm module), I can deploy the source CSS as an emergency solution. Performance may perhaps take a hit, but a slightly slower site is likely better than a site with broken or no CSS until the build process can be fixed. I don’t want to have to wait for compilation before seeing the results of my CSS changes. Processing time may be anything from negligible to frustrating, obviously, but if it takes longer than the time it takes for me to switch from my code editor to my browser and reload the page (≈1s) it’s too slow. I’m fully aware that many people who use CSS preprocessors will disagree with most or all of the above. I already know that so no need to tell me :-). However, me not using Sass or other CSS preprocessors like cssnext does not mean I don’t use CSS processors. The difference, as I see it, is whether or not your CSS requires compilation before browsers can understand it, which I really want to avoid. I use PostCSS (with third party plugins and ones I’ve written myself) and CSScomb as helpers for things like: sorting declarations and fixing coding style issues with CSScomb automatically inserting vendor prefixes wherever they are necessary (or removing them wherever they’re not) inserting fallbacks for custom properties linting CSS I set up both CSScomb and PostCSS to work on my source CSS, which means I always see the results. No black boxes. I can save my file and reload instantly without having to wait for compilation (since the changes are mostly cosmetic and vendor prefixes/fallbacks only need to be inserted once). But the tools save me some typing and fix most coding style inconsistencies for me. That’s my kind of CSS processing. Posted in CSS.Copyright © Roger Johansson

Posted on: 26 March 2016 | 6:00 pm

Cutting down on vendor prefixes

Most web developers currently use vendor prefixes in CSS to enable certain features in some browsers. That’s fine, but sometimes I see code examples and prefix-adding tools that go a bit overboard with the support and add every possible prefix that has ever been in use (and sometimes even ones that were never used). I think there are a bunch of CSS properties that we can safely stop using vendor prefixes for, or at least considerably cut down on the number of prefixes. In the examples that follow I note which prefixes, if any, that I currently use. I have only included CSS properties that are often used with several vendor prefixes but could very well lose all of them or just keep a single one. You may be thinking “But no! You’re shutting out people using older versions of browser X!” No, this is not about shutting anyone out or not “supporting” a certain browser version. It is about using progressive enhancement to make your CSS smaller and easier to handle and maintain. We’re not talking about essential features here. If a browser doesn’t support an unprefixed property, well, there won’t be any rounded corners or shadows or gradients or whatever. The result will look the way it does in IE8, which currently often has a lot more users than, say, Firefox 3.6 or Chrome 9 or Safari for iOS 4 or some other old browser version that may need a vendor prefix. As long as the entire layout doesn’t crash when something isn’t supported, that’s OK in general, given that at least the latest couple of versions of all major browsers will apply your CSS. border-radius No vendor prefixes. .example { border-radius:10px; } Current browser support for border-radius. box-shadow No vendor prefixes. .example { box-shadow:0 0 5px rgba(0,0,0,0.5); } Current browser support for box-shadow. background-origin, background-size and background-clip No vendor prefixes. .example { background-origin:content-box; background-size:100% auto; background-clip:content-box; } Current browser support for CSS3 Backgrounds. Gradients Gradients (linear-gradient and radial-gradient) are probably the properties where you have the most to save by cutting down on prefixes. I don’t go completely prefix-less here, but I only use the -webkit- prefix (and not the old WebKit syntax). So instead of something like this, which you get from many of the tools that add vendor prefixes: .overkill-example { background:#f9f9f9; background:-moz-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#f2f2f2)); background:-webkit-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); background:-o-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); background:-ms-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); background:linear-gradient(to bottom, #ffffff 0%, #f2f2f2 100%); filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#f2f2f2',GradientType=0 ); } I would use this: .example { background:#f9f9f9; background:-webkit-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); background:linear-gradient(to bottom, #ffffff 0%, #f2f2f2 100%); } That’s just one declaration extra. And Looking at the browser support for CSS gradients I think I’ll be dropping that too within a year or so. calc() I only use the -webkit- prefix for this one. .example { background-position:100% 100%; background-position:-webkit-calc(100% + 30px) -webkit-calc(100% + 16px); background-position:calc(100% + 30px) calc(100% + 16px); } Note that you may want to use some caution with calc(). If you use it on layout-affecting properties, make sure there is a fallback declaration for browsers that don’t support it so they don’t get a total trainwreck. Current browser support for calc(). Transitions For transitions I only use the -webkit- prefix: .example { -webkit-transition:background-position 0.5s; transition:background-position 0.5s; } As with gradients I don’t think it will be very long before I go completely prefix-less with transitions. Current browser support for CSS Transitions. Adapt to your scenario The above are examples of how I currently deal with vendor prefixes for these CSS properties. If you, or your clients, have loads of users on old versions such as Firefox 3.6 or iOS 2.1, you may need to use more prefixes if progressively enhancing the visual appearance is not acceptable. Personally I have yet to receive a bug report related to omitting prefixes as described here, but then I do make an effort to explain progressive enhancement to the client early on. Posted in CSS.Copyright © Roger Johansson

Posted on: 12 November 2013 | 6:00 pm

Full-width justified vertically centered navbar

In a couple of recent projects I’ve faced designs where the main navigation bar gave me more trouble than usual. These are the prerequisites that make the problem tricky to solve: The navbar is full-width and the links have to fill up the entire width regardless of how many of them there are The text in each link needs to be vertically centered and wrap to multiple lines if necessary The entire area of each item in the navbar needs to be clickable After exploring lots of different methods I’ve found two solutions to the problem. As is often the case, both have their drawbacks and you need to choose which compromise to make. Examples of both solutions can be found on the Full-width justified vertically centered navbar demo page. Solution 1: standard list + links markup pattern The first solution uses this very common markup pattern for groups of navigational links: <div class="nav-main" role="navigation"> <ul> <li><a href="/">Section</a></li> <li><a href="/">Section</a></li> <li><a href="/">Section</a></li> </ul> </div> Making that display as intended is not a big deal actually, if you can disregard IE7. Just use display:table and display:table-cell. Here’s the CSS you need: .nav-main ul { display:table; border-collapse:collapse; width:100%; margin:0 0 20px; padding:0; list-style:none; } .nav-main li { display:table-cell; width:1%; border:1px solid #ddd; background:#eee; vertical-align:middle; text-align:center; } .nav-main a { display:block; padding:10px 4px; color:#000; text-decoration:none; } That CSS gets us the look we want. But the problem is that only the a element is clickable, and it doesn’t extend to the entire height of the li element. If some of the links line wrap but not others, the entire area is clickable only in the navigation items that have wrapped text (and in case some links wrap onto three or more lines, only those that have the highest number of text line). If you don’t get any line wrapped links in the demo, just make your browser window narrower to see what I mean. You could avoid line-wrapping by adding a white-space:nowrap declaration, but in this case one of the requirements is that links can wrap if necessary. The result is that if you add some styling to the links when they are hovered over or receive keyboard focus, it will be obvious that single-line links don’t cover the entire area. And when you click one of the items, nothing happens unless you click on the actual link. Creating a hover effect is easy: .nav-main li:hover { }. But that does nothing for keyboard users, and it does not make the li elements clickable. If there is a pure CSS solution to this (using the same markup) I’d be happy to hear it, but I have not been able to find one or figure one out. So I added a little bit of JavaScript (jQuery-based) to fix it: $('.nav-main').each(function () { var nav = $(this); // Give the containing element a class name to let the CSS know it is active nav.addClass('active'); nav.find('li').each(function () { var item = $(this); var link = item.find('a'); var href = link.attr('href'); // When an li element is clicked, open the href of the link it contains item.click(function (e) { if (!$(e.target).is(link)) { // Check if a key that indicates that the user wants the link to open in a new tab or window is pressed. See https://github.com/Lingonmirakel/smartclick. if (e.ctrlKey || e.metaKey || e.which === 2) { window.open(href, ''); } else { window.location = href; } } }); // Set a class on the li when the link gets focus to enable visual feedback for keyboard navigation link.focus(function () { item.addClass('focus'); }).blur(function () { item.removeClass('focus'); }); }); }); The script does a few things: Gives the .nav-main element an “active” class name that is used to set cursor:pointer on the li elements to indicate that theuy are clickable Makes clicks on an li element open the href of its contained link Toggles a ”focus” class name on the li elements when their contained link receives or loses keyboard focus With that in place you can style the hover and focus states like this (note the use of .focus instead of :focus): .nav-main a:hover, .nav-main a:focus { outline:none; color:#fff; background:#000; } .nav-main.active li:hover { cursor:pointer; } .nav-main.active li:hover, .nav-main.active li.focus { background:#000; } .nav-main.active li:hover a { color:#fff; } You may wonder about outline:none in that first rule. I’ve removed it because otherwise it would reveal that the link doesn’t cover the whole list item, and in this example it’s pretty obvious visually which link has focus even without the focus ring. If JavaScript is off, the “full-height” clickability illusion will be ruined, but the links will still be there and fully functional. Solution 2: Links not in a list The problem can actually be solved without JavaScript if you do not put the links in a list, like this: <div class="nav-main" role="navigation"> <a href="/">Home</a> <a href="/">Section two</a> <a href="/">Section three</a> <a href="/">Another section</a> <a href="/">A section with a longer name</a> <a href="/">Section six</a> <a href="/">This is section seven</a> <a href="/">Section 8</a> </div> Here’s the corresponding CSS: .nav-main { display:table; border-collapse:collapse; width:100%; margin:0 0 20px; } .nav-main a { display:table-cell; width:1%; padding:10px; border:1px solid #ddd; outline:none; background:#eee; color:#000; text-decoration:none; vertical-align:middle; text-align:center; } .nav-main a:hover, .nav-main a:focus { background:#000; color:#fff; } Done. Much simpler than having to involve JavaScript. But see the caveat in the next section before picking this solution. To list or not to list The code for the second solution is a lot simpler, but it does require deviating from the standard markup pattern for navigation (for a much longer discussion about using lists or not for navigation, see Wrapup of Navigation in Lists). This deviation isn’t necessarily a huge problem, but my personal preference is to stick with the list pattern. Looking at specifications, the HTML5 spec for the nav element says this: In cases where the content of a nav element represents a list of items, use list markup to aid understanding and navigation. I haven’t used nav elements here, instead opting for div elements with role="navigation", which is equivalent but doesn’t affect the document outline, so I’d say the above applies. Using a list also lets screen reader users know up-front how many links the navigation contains and is suggested in the WCAG 2.0 technique H48: Using ol, ul and dl for lists or groups of links. And finally it is a well-established markup pattern that just feels right, so I’d want a really good reason to use something else. Posted in CSS, JavaScript.Copyright © Roger Johansson

Posted on: 12 October 2013 | 7:00 pm

Responsive scrollable tables

Over six years ago I wrote a short post about preventing HTML tables from becoming too wide. The solutions I offered in that post involve using table-layout:fixed to lock down the width of tables. While that may work in some cases, it often will not be very pleasant to use. Since I wrote that post, many, many small screen devices that you can use to browse the web have been released, which means that the risk of people encountering a data table that is too wide to fit their browser window is greater than ever. There are already several different strategies for dealing with data tables on small screens, involving things like flipping tables, hiding columns, rearranging data cells, and making over-wide tables scrollable. See Responsive Data Table Roundup at CSS-Tricks for some examples. Every technique for making tables flexible (or “responsive”) that I have seen comes with its own set of drawbacks. That’s expected really – I don’t think this is a problem that can be solved perfectly, so we have to compromise somehow. But I do think that one of the simplest and least inelegant ways to handle data tables is to make them horizontally scrollable when necessary, and so I thought I’d describe how I do that. In case the following seems familiar, it may be because Russ Weakley describes a pretty similar technique in A simple (and very rough) responsive table solution. The concept is the same, but some details differ. To see the end result, take a look at the Responsive scrollable tables demo page. CSS To be able to scroll the entire table you need to put it inside a container element with overflow scrolling enabled. The CSS that creates the scrollbar is very simple. If you don’t want or need anything more than the scrollbar as a visual indicator of scrollability, you could get away with this: .scrollable { overflow-x:auto; } I personally think doing a bit more than that both makes it easier to realise that the entire table is not visible and makes it look better. There are many ways you can do that, but in the demo I’ve used a rotated version of the pseudo-element technique I describe in Responsive drop shadows. To make this work you need an extra wrapper element and an overflow:hidden declaration on the outer wrapper, making the entire CSS look like this: .scrollable.has-scroll { position:relative; overflow:hidden; /* Clips the shadow created with the pseudo-element in the next rule. Not necessary for the actual scrolling. */ } .scrollable.has-scroll:after { position:absolute; top:0; left:100%; width:50px; height:100%; border-radius:10px 0 0 10px / 50% 0 0 50%; box-shadow:-5px 0 10px rgba(0, 0, 0, 0.25); content:''; } /* This is the element whose content will be scrolled if necessary */ .scrollable.has-scroll > div { overflow-x:auto; } Feel free to change the shadow as you see fit, or replace it with something completely different. Since scrollbars are not very visible until you scroll in iOS and Android WebKit browsers (and on OS X depending on user settings), it may be a good idea to make them explicitly visible so users will notice that they can scroll the table. We can do this with some WebKit-only CSS: .scrollable > div::-webkit-scrollbar { height:12px; } .scrollable > div::-webkit-scrollbar-track { box-shadow:0 0 2px rgba(0,0,0,0.15) inset; background:#f0f0f0; } .scrollable > div::-webkit-scrollbar-thumb { border-radius:6px; background:#ccc; } JavaScript While this technique is mostly CSS-based and could be used with CSS alone, I’ve added a bit of JavaScript. Sometimes you can have full control of the markup used for data tables, but it can be tricky for tables created by a WYSIWYG editor in a CMS, for example. So instead of relying on the wrapping div elements being in the markup I add them with a bit of JavaScript (jQuery-flavoured in this example, but it could be re-written in plain JavaScript, or turned into a jQuery plugin): // Run on window load instead of on DOM Ready in case images or other scripts affect element widths $(window).on('load', function() { // Check all tables. You may need to be more restrictive. $('table').each(function() { var element = $(this); // Create the wrapper element var scrollWrapper = $('<div />', { 'class': 'scrollable', 'html': '<div />' // The inner div is needed for styling }).insertBefore(element); // Store a reference to the wrapper element element.data('scrollWrapper', scrollWrapper); // Move the scrollable element inside the wrapper element element.appendTo(scrollWrapper.find('div')); // Check if the element is wider than its parent and thus needs to be scrollable if (element.outerWidth() > element.parent().outerWidth()) { element.data('scrollWrapper').addClass('has-scroll'); } // When the viewport size is changed, check again if the element needs to be scrollable $(window).on('resize orientationchange', function() { if (element.outerWidth() > element.parent().outerWidth()) { element.data('scrollWrapper').addClass('has-scroll'); } else { element.data('scrollWrapper').removeClass('has-scroll'); } }); }); }); Besides not having to put the wrapper elements in the markup, doing it this way lets you use different styling when tables actually can be scrolled. The most obvious example in my demo is the shadow that appears on the right hand side of the table when it is scrollable. Note that this function isn’t limited to tables. You can apply this to any element that potentially will be wider than its parent. A possible use case would be figures with images that you don’t want to scale down. The downside to using JavaScript for this is of course that if JavaScript is off, tables won’t be scrollable and users will have to scroll the entire page horizontally, just like without this. For tables that you can control the markup of (and around), you can add the wrapper elements to the source and rewrite the script to avoid inserting the wrappers if they already exist, giving non-JS users almost the same result – the difference being that the styling will be the same even if the table doesn’t actually need to be scrolled. Browser support This technique works in all desktop browsers I have tested in, down to IE7. Obviously the shadow won’t appear in IE8 and below due to lack of support for box-shadow and border-radius (and in the case of IE7, lack of support for the :before and :after pseudo-elements). There will still be a horizontal scrollbar though, so I think that’s acceptable. It also works in newer mobile browsers, but in some older mobile browsers (iOS 4 and Android 2 for instance) support for overflow scrolling isn’t quite up to it. If that is a concern you may want to use something like Modernizr to check for support before applying the CSS. Not just for small screens While this technique may be especially useful on small screen devices, there is no reason to limit the use to touch devices or devices with screen (or window) sizes below a certain width. Users of desktop browsers benefit from this too – remember that there are plenty of people who do not have a large widescreen monitor and maximise their browser window. And sometimes data tables are just too large to fit inside your layout. Posted in CSS, JavaScript.Copyright © Roger Johansson

Posted on: 20 September 2013 | 7:00 pm

Height in percent when parent has min-height and no height

When trying to force an element to always extend to the height of its parent I ran into some peculiar browser behaviour that I thought was worth mentioning. Here’s the situation: The parent element has a min-height specified (in pixels), but no height The child’s height is set to 100% I was expecting the child to get the same height as its parent, but that is not what happens. What happens instead may well be according to the CSS 2.1 Specification, but a bit nonintuitive, at least to me. What the specification says Here’s what the CSS 2.1 specification says about heights set in percent: The percentage is calculated with respect to the height of the generated box’s containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to ‘auto’. I interpret the containing block in this case to be the parent element. In my example it doesn’t have an explicit height, but it does have a min-height, so its height only partly depends on content height. What about min-height, then? The min-height section in the CSS 2.1 specification says this about min-height values with a length unit: Specifies a fixed minimum or maximum computed height. To me it sounds like this should be considered when calculating percentage heights of children. But browsers do not, so apparently I am not reading the specification correctly. What browsers do All browsers I have tested in ignore height:100% on the child element and make its height the height of its content. While not what I wanted, at least it’s cross-browser. While fiddling with this problem I tried giving the parent element a height of one pixel. And now things get interesting as the result of that differs between browsers. This would probably be easier to understand if all browsers behaved the same way. But they don’t. The following browsers do not set the child element’s height (specified in percent) based on its parent’s computed height if only min-height is used: Safari 6.0.5 Safari for iOS 6.1 Opera 12.15 IE 8 But these browsers will expand the child element’s percentage height to its parent’s min-height if the parent also has a height specified, even if it is only one pixel: Firefox 21 WebKit Nightly (verified with r151959) Chrome 27 IE 7, 9, 10 Take a look at the Height in percent when parent has min-height and no height demo page to see the difference. Once Safari gets updated and Opera switches to WebKit I would guess that browsers will all behave like the latter bunch since the latest WebKit nightly build does. I don’t really understand why giving the parent element a 1px height has this effect, but it’s what the browsers do. Another interesting thing that happens when the parent element has both height and min-height specified with the same unit: if its content makes the element taller than its min-height, the content will overflow as if the min-height magically turns into height. The child element’s computed height will remain at the parent’s specified min-height though. As far as I can tell all browsers behave the same in this regard, so unfortunately you can’t just add height:1px to the parent element and solve the problem. What developers expect Speaking for myself, the intuitive behaviour in this case would be to let the value used to calculate heights in percent be the parent’s computed height. If the parent has no explicit height but a given min-height, that value should be used for the computed height (depending on which box-sizing model is used paddings and borders may also be relevant). No solution or magic trick offered here, just an observation of browser behaviour that I wasn’t really expecting.Posted in CSS.Copyright © Roger Johansson

Posted on: 27 June 2013 | 7:00 pm

How to proportionally scale images that have dimension attributes

Allowing images to scale along with their container is an important part of responsive web design (and was so even before the term “responsive web design” existed). It’s really quite easy – all you need to do is give the image a width (or max-width) in percent: img { max-width:100%; } This will prevent any img element from getting wider than its container. If the container is narrower than the image, the image will scale down. But there is a catch. If an img element has dimension attributes (width and height) in the markup and you override the width with CSS, the image will remain the height that is specified in the HTML while its width changes. That doesn’t look good. An easy way to avoid the problem is to simply not specify width and height for images. But specifying what dimensions images have is recommended for performance reasons as it can improve rendering speed in the browser. See Google’s advise in Specifying image dimensions for more. The image size doesn’t have to be in the HTML – it can also be in the CSS. Most of the time I find it more practical and logical to use the HTML attributes. So you’ll want to specify image dimensions and find another way to make them scale proportionally. Fortunately it’s easy: just add height:auto along with the max-width: img { max-width:100%; height:auto; } This overrides any height attributes in the HTML and lets the image scale properly. See the How to proportionally scale images that have dimension attributes demo page for examples. Browser notes Even with something as seemingly simple as this there are a couple of browser differences to be aware of, at least if you’re allowing IE8 and below to get a flexible width layout. IE7 actually scales the image proportionally whether or not there are any dimension attributes in the markup, even if you do not specify height:auto. For IE8 to scale images properly, however, you need to give them a width in addition to height:auto. Fortunately width:auto will do the trick without causing problems in the other browsers. So if you need proportional image scaling in IE8, use this: img { width:auto; max-width:100%; height:auto; } Posted in CSS.Copyright © Roger Johansson

Posted on: 12 June 2013 | 7:00 pm

Firefox and the magical text-overflow:ellipsis z-index

A while ago I received a strange bug report for a site I’d been working on. The report mentioned dots appearing on top of a dropdown menu when it was expanded. I had a look in Safari, could not see any dots, but then tried Firefox. And sure enough, there were sets of three dots in the dropdown menu. It didn’t take long to find the cause, fortunately. Just below the dropdown menu was a list of news items whose text-overflow value was set to ellipsis. The dots in the dropdown menu were the ellipsis characters peeking through, or being rendered on top of, the dropdown’s background. After checking in a lot of different browsers I can only replicate this in Firefox. Apparently the ellipsis rendered by text-overflow gets a z-index that is higher than the element it is applied to. It also appears above any absolutely or relatively positioned elements that come before the element with text-overflow in the source order, unless those elements have a z-index value greater than 0. Open the Firefox and the magical text-overflow:ellipsis z-index demo page to see an example. Luckily this was easy to fix in my case by giving the positioned element (the dropdown menu in this case) a z-index. You could argue that you should always do that to make sure anything that is absolutely positioned gets rendered on top of other elements (if that is in fact what you want), but then it shouldn’t always be necessary. After reading the specification for text-overflow, and given that no other browser renders the ellipsis on top of positioned elements, this looks like a Firefox bug to me. Yeah, this is a pretty minor thing, but in case you too get a bug report mentioning mysterious dots in Firefox, you know what to look for now. Posted in CSS, Browsers.Copyright © Roger Johansson

Posted on: 30 May 2013 | 7:00 pm

Replacing images when printing

It isn’t all that uncommon that, after you’ve polished your print stylesheet to make a site look well on paper as well as on screen, you realise that the logo really doesn’t look its best. It may look blurry or pixelated on paper due to having a pixel density intended for screen viewing, of course. But even worse, its edges may look ugly or it may actually be invisible because whatever is behind it when viewed on screen isn’t printed. Applying a background colour to the logo image or its containing element in the print CSS isn’t going to help either since most browsers by default do not print backgrounds at all. If you can’t change the image used for screen so that it will look good in print as well, you need to somehow make browsers use a different image when printing. One way of doing that is by using CSS generated content. Hide the screen image, insert one for printing A pretty straightforward way to exchange the images is to hide the screen image and use the print image as content for a CSS pseudo-element. Assume you have the following HTML: <div id="logo"> <img src="screen-logo.png" width="200" height="35" alt="The Awesome Logo" /> </div> To hide that image and insert another one, all you need is this CSS: @media print { #logo img { display:none; } #logo:after { content:url(print-logo.png); } } This works in most browsers. Chrome, IE 9+, Opera, and Safari all print the image content of the pseudo-element. Unfortunately, Firefox versions older than 20 do not, and neither does IE 8. (Neither does IE 7 since it doesn’t support CSS generated content, but let’s not worry about that right now.) The problem browsers IE 8 apparently treats pseudo-element content images as backgrounds when printing, since it does print the image if you check “Print Background Colors and Images” in the Page Setup dialog. So that explains that problem. Firefox (19 and older) is more of a mystery, however. Whether the image is printed or not seems a bit random. It seems as if the page is fetched from cache, the image is printed, but if you do a full refresh it is not. It also gets printed if you do a print preview, cancel printing, then do a print preview again. As far as I can tell the behaviour is similar for both Mac and Windows versions of Firefox. Possibly even more confusing, changing the media type to all also makes Firefox always print the replacement image: @media all { #logo img { display:none; } #logo:after { content:url(print-logo.png); } } But you don’t want that since that would display the print image on screen. Reverse the process You may or may not (most likely not – yet) be able to ignore the problem for IE8, but probably not for Firefox 19 and older just yet. A workaround is to reverse the process: reference the print image in the HTML and replace it with the screen image in the screen CSS. The HTML: <div id="logo"> <img src="print-logo.png" width="200" height="35" alt="The Awesome Logo" /> </div> The CSS: @media screen { #logo img { display:none; } #logo:after { content:url(screen-logo.png); } } No print CSS is needed to make the print image appear this time. And it works in IE 8 and Firefox 19- in addition to the other browsers. The drawbacks are that browsers without CSS support will display the print image on screen, and that browsers without support for the :after pseudo-element will display nothing. To avoid the second problem, which mainly affects IE7 and older, you can use you favourite IE CSS patching method to override the display:none declaration for the image. The Replacing images when printing demo page contains an example of each method. In the demo I’ve used a screen image that contains white text on a transparent background and a print image that has a black background. In the screen CSS I’ve given the element containing the logo a background colour to make the logo text visible. Use cases So when would you want to replace images like this? When you want to inverse a logo in print When you want higher resolution images for printing When an image that you want to print has a transparent background that makes it ugly, illegible or invisible in print There may be more use cases as well as other methods, of course. Posted in CSS.Copyright © Roger Johansson

Posted on: 13 May 2013 | 7:00 pm