By Lea Verou
Question: What bugs you the most when coding CSS (2.1) today?
IMHO:
CSS3 attempts to solve these problems
background: url('/colors/black-0.75.png');
* Assumes latest beta
<div class="foo">
<div class="inner">
<div class="inner2">
<div class="inner3"></div>
</div>
</div>
</div>
.foo {
background: url(img/corner_tr.png) top right no-repeat;
}
.foo .inner {
background: url(img/corner_br.png) bottom right no-repeat;
}
.foo .inner2 {
background: url(img/corner_tl.png) top left no-repeat;
}
.foo .inner3 {
background: url(img/corner_bl.png) bottom left no-repeat;
}
border-radius:
20px
border-radius:
40px
/
20px
border-radius:
40px
10px
border-radius:
40px
50%
0
border-radius:
40px
50%
0
10px
Note: There are also individual properties for that, e.g. border-top-left-radius
* Assumes latest beta
<div class="wrap1"><div class="wrap2">
<div class="wrap3"><img src="object.gif" alt="The object casting a shadow" /></div>
</div></div>
.wrap1, .wrap2, .wrap3 {
display:inline-table;
/* \*/display:block;/**/
}
.wrap1 {
float:left;
background:url(shadow.gif) right bottom no-repeat;
}
.wrap2 { background:url(corner_bl.gif) left bottom no-repeat; }
.wrap3 {
padding:0 4px 4px 0;
background:url(corner_tr.gif) right top no-repeat;
}
box-shadow:
10px
5px
15px
rgba(0,0,0,.5)
box-shadow:
10px
5px
15px
black
inset
box-shadow:
20px
20px
15px
-15px
#f09
Multiple shadows, for complex effects:
box-shadow: 0 2px 6px rgba(0,0,0, .5), 0 1px rgba(255,255,255, .3) inset, 0 10px rgba(255,255,255, .2) inset, 0 10px 20px rgba(255,255,255, .25) inset, 0 -15px 30px rgba(0,0,0, .3);Example originally conceived by Jan Henrik Helmers
* Assumes latest beta
<h1><img src="heading.png" alt="Heading text"
width="300" height="50" /></h1>
or, the slightly better:
<h1>Heading text</h1>
h1 {
background: url(heading.png) no-repeat;
width: 300px;
height: 50px;
text-indent:-9999px;
}
text-shadow:
1px
.1em
.3em
black
I'm glowing
I have a rudimentary outline
You drank too much
Burning hot
* Assumes latest beta
background: #f09 url(linear-gradient.png) top repeat-x;
background: #f09 url(radial-gradient.png) top left no-repeat;
background:
linear-gradient(
#f09
,
black
)
linear-gradient(
-45deg
,
#f09
,
black
)
linear-gradient(
white
,
#f09
,
black
)
linear-gradient(
white
,
#f09 20%
,
black
)
radial-gradient(
#f09
,
transparent
)
* Assumes latest beta
<img src="rotated-with-text.png" alt="…" />
.foo {
background: url(rotated-box.png) no-repeat;
width:200px;
height:200px;
padding:20px;
overflow:auto;
}
transform:
rotate(
-30deg
)
transform:
skew(
30deg
,
-10deg
)
More than just rotate and skew:
transform:
rotate(30deg)
skewX(30deg)
* Assumes latest beta
Multiple containers, 1 for each background image
<div class="foo">
<div class="inner">
<div class="inner2"></div>
</div>
</div>
.foo { background: url(first_image.png); }
.foo .inner { background: url(second_image.png); }
.foo .inner2 { background: url(third_image.png); }
* Assumes latest beta
3 containers for fixed width or height, 4+ for fluid boxes
<div class="foo">
<div class="inner">
<div class="inner2"></div>
</div>
</div>
.foo {
background: url(img/border_top.png) top no-repeat;
padding-top:10px;
}
.foo .inner {
background: url(img/border_bottom.png) bottom no-repeat;
padding-bottom:10px;
}
.foo .inner2 {
background: url(img/border_middle.png) repeat-y;
}
border-image:
url(border-image.png)
14
repeat
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
* Assumes latest beta
Using server side code or JavaScript to end up with something like that:
<ul> <li class="odd"></li> <li></li> <li class="odd div3"></li> <li></li> <li class="odd"></li> <li class="div3"></li> </ul>
:nth-child
(
odd
)
:nth-child
(
3n
)
:nth-child
(
3n+2
)
Note: Actually even
== 2n
and odd
== 2n+1
:nth-last-child()
: Starts counting from the end:nth-of-type()
: Counts elements of the same tag name separately:first-child
== :nth-child(1)
and
:last-child
== :nth-last-child(1)
:only-child
== :first-child:last-child
* Assumes latest beta
Writing 2 CSS rules for every negation we wanted
.post { font-size:75%; } .post:first-child { font-size: inherit; }
.post
:not
(
:first-child
)
{ font-size: 75%; }
p:not(h1 + p)
or even p:not([class][title])
are not possible yet:not()
pseudo-class doesn't* Assumes latest beta
.icon { background: url('some-icon.png'); width: 32px; height: 32px; text-indent: -9999px; }
.icon { content: url('some-icon.png'); }
* Assumes latest beta
transition:
1.5s
opacity
ease-out
transition:
2s opacity
,
.5s height ease-in
transition:
.5s height
,
.5s
.5s
width
Also available as a separate property (transition-delay
)
* Assumes latest beta
Check every few ms if the hash changed (no hashchange
event in those days) and do stuff, like:
var oldHash = location.hash; setInterval(function(){ if(location.hash != oldHash) { oldHash = location.hash; var targetHeading = document.getElementById(location.hash.substr(1)); if(targetHeading) { targetHeading.className = 'target'; } } }, 500);
:target
pseudo-classThis very slide is visible due to :target
:
.slide { z-index:1; opacity:0; } .slide:target { z-index:100; opacity:1; }
* Assumes latest beta
checkbox.addEventListener('change', function(){ var classes = this.nextElementSibling.classList; if(this.checked) { classes.add('checkboxChecked'); } else { classes.remove('checkboxChecked'); } });
Even worse in actual situations, where older browsers matter
* Assumes latest beta
element.style.width = element.getAttribute('data-percent') + '%';
width:
attr
(
data-percent
,
%
,
0
)
* Assumes latest beta
Setting the CSS property through JavaScript, performing the calculations on the computed styles, like:
var element = $(…); element.css('width', .5 * $(element).parent().css('width') - element.css('borderLeftWidth') - element.css('borderRightWidth') - element.css('paddingLeft') - element.css('paddingRight') );
or just giving up altogether and using a very rough estimate (e.g. 48%)
padding: .5em; border: 1px solid; width: calc(50% - 2*.5em - 2*1px);
attr()
values for calculations* Assumes latest beta
var innerWidth = window.innerWidth || (document.documentElement? document.documentElement.clientWidth : 0 ) || document.body.clientWidth; element.style.width = .5 * innerWidth + 'px';
width:
.5
vw
vh
: viewport heightvm
: minimum of the tworem
: Root element's em font size* Assumes latest beta
* Assumes latest beta
Browsers ignore stuff they don’t understand
That includes:
If a CSS property is defined twice in the same rule, only the last one counts
background: black; background: rgba(0, 0, 0, .75);
Just include all of them, browsers will pick the one they understand
-moz-transition: 1s ease-in; -webkit-transition: 1s ease-in; -o-transition: 1s ease-in; transition: 1s ease-in;
Put the prefix-less version last
function isPropertySupported(property) { if(property in document.body.style) return true; var prefixes = ['Moz', 'Webkit', 'O', 'ms', 'Khtml'], prefProperty = property.charAt(0).toUpperCase() + property.substr(1); for(var i=0; i<prefixes.length; i++) { if((prefixes[i] + prefProperty) in document.body.style) return true; } return false; }
function isRGBASupported() { var element = document.createElement('div'); try { element.style.color = 'rgba(0,0,0,.5)'; } catch(e) { return false; } return !!element.style.color; }
function isSelectorSupported(selector) { try { document.querySelector(selector); return true; } catch(e) { return false; } }
Credits: