Amélioration progressive : Modernizr et sélecteurs CSS avancés

Astuce par (Intégrateur du Dimanche, Strasbourg)
Créé le , mis à jour le (74187 lectures)
Tags : css, xhtml, commentaires, hacks, ie8, css3, cibler, root, progressif, lang, amélioration, conditionnels, détecter

A l'inverse du concept de dégradation gracieuse, le principe d’amélioration progressive ("progressive enhancement" en anglais) est une stratégie de conception web en couches successives, qui permet à chacun d’accéder au contenu et aux fonctionnalités de base d’une page web en utilisant n’importe quel navigateur, tout en offrant une version améliorée aux utilisateurs disposant de navigateurs plus récents ou plus évolués.

En pratique et dans le domaine des styles CSS, cela se traduit par une mise en forme initiale commune à l'ensemble des logiciels de navigation, puis un "bonus" pour agrémenter ceux qui ne supportent pas encore CSS3 ou mal CSS2.1.

Cela permet d’opter occasionnellement pour une technologie récente telle que CSS3 pour certaines décorations d’éléments de page (coins arrondis, ombrages, semi-transparence, transitions progressives…) qui pourraient consister en des « bonus » mérités pour les navigateurs récents. Ces ornements pourraient également être traités sans CSS3 à l’aide de méthodes plus longues et coûteuses en performances (blocs imbriqués, arrière-plans multiples, JavaScript, …).

L'un des meilleurs représentant de ce concept est le site web de Twitter.com dont l'affichage est différent selon les navigateurs : sur IE8 et inférieurs, de nombreux coins de blocs sont carrés,… et deviennent arrondis sur les navigateurs modernes. Il en est de même pour certaines transparences de couleurs.

Modernizr : le bazooka JavaScript

Modernizr

Modernizr est une librairie JavaScript autonome dont la fonction est de détecter les aptitudes spécifiques du navigateur. Son support est extrêmement étendu et concerne autant HTML5 (Geolocation, localstorage, drag and drop, SVG, web sockets, audio, vidéo,…) que CSS3 (@font-face, border-radius, transitions, animations, opacity, text-shadow, flexible box model,…).

Dans la pratique, Modernizr ajoute automatiquement pour chaque fonctionnalité une classe au sein de la balise <html>, et il suffit ensuite d'exploiter la classe souhaitée, ou bien d'interroger par JavaScript la présence d'une API.

.element { /* Pour les navigateurs ne reconnaissant pas CSS3 border-image */  
   border: 1px inset #666;
}
.borderimage .element {  /* Pour les navigateurs reconnaissant border-image */ 
   border: none;
   -moz-border-image: url(border.png) 0 5 0 5 stretch;
   -webkit-border-image: url(border.png) 0 5 0 5 stretch;
   border-image: url(border.png) 0 5 0 5 stretch;
}

L'inconvénient de cette méthode - outre l'ajout d'une couche JavaScript non négligeable - est la complexité globale et la panoplie de classes multiples dont est affublée la balise <html> :

Classes de Modernizr

Tirer parti des sélecteurs CSS avancés

Les sélecteurs CSS récents permettent eux aussi de cibler uniquement les navigateurs modernes et de modifier les styles des éléments en conséquence.
Au cas par cas, ce type de solution peut se révéler bien plus souple à l'usage qu'un outil tel que Modernizr.

:root pour IE9 et supérieurs

La pseudo-classe CSS3 :root, est simple à utiliser et est comprise par tous les navigateurs modernes sauf Internet Explorer (IE8 compris).

Si vous souhaitez cibler rapidement et simplement les navigateurs supportant la propriété border-radius, ainsi que les transparences de couleur, il suffit de procéder ainsi :

element {   /* Pour tout le monde */
  border: 1px solid black;
  background-color: #fff;
}  
:root element {   /* Pour les navigateurs modernes (CSS3 uniquement) */ 
  border: 1px solid rgba(0,0,0,0.8); 
  background-color: rgba(255,255,255,0.6);
  -moz-border-radius: 6px;
  -webkit-border-radius: 6px;
  border-radius: 6px;
} 

Autre exemple, expérimenter le modèle de boîte flexible CSS3 :

#boite {   /* Pour tout le monde */
  display: block; 
  float: left; 
}  
:root #boite {   /* Pour les navigateurs modernes (CSS3 uniquement) */  
  display : -moz-box; 
  display : -webkit-box; 
  display : box; 
  float: none; 
}

:lang à partir d'IE8

Le sélecteur :lang() a l'avantage d'être reconnu à partir de IE8.
Il est donc possible de cibler tous les navigateurs actuels à l'aide d'un sélecteur associé à :lang(fr). Cette astuce suppose bien entendu que l'attribut HTML lang, soit appliqué à un élément de structure principal (généralement la balise <html>) et qu'il ait pour valeur "fr" !

<html lang="fr">

Ce type de sélecteur peut nous aider à employer un schéma de positionnement à l'aide de table-cell (note : au cas par cas, il pourrait être plus judicieux d'utiliser un commentaire conditionnel ciblant IE7 et inférieur).

#boite { /* Pour tout le monde, dont IE6/IE7 */ 
  float: left; 
  width: 300px; 
} 
#boite:lang(fr) {  /* Pour les navigateurs modernes ainsi que IE8 */ 
  display: table-cell; 
  float: none; 
  width: auto; 
}

Autre suggestion : positionner à l'aide de inline-block.

#boite { /* Pour IE6/IE7 et les anciens navigateurs */ 
  display: inline; 
  zoom: 1;
}
#boite:lang(fr) {  /* Pour les navigateurs modernes et IE8 */ 
  display: inline-block; 
}

Ne cibler qu'Internet Explorer : les commentaires conditionnels

Vous le savez déjà certainement, les commentaires conditionnels sont un mécanisme propre à Internet Explorer Windows, qui permettent d'inclure dans une page (X)HTML, de manière valide, du code qui ne sera lu et interprété que par Internet Explorer, ou par l'une ou l'autre de ses versions.

Ce billet ne va pas s'attarder sur ce concept puisqu'un article sur les commentaires conditionnels existe déjà sur Alsacréations. Si votre souhait est de ne cibler que le navigateur de Microsoft (ou l'une de ses versions spécifiques) afin de corriger des défauts d'affichage ou des déficiences, la meilleure solution demeure l'usage des commentaires conditionnels.

Ressources

Commentaires

Ladytron a dit le

Très intéressant, j'avais pas encore songé à ce genre de méthode pour filtrer IE.
A ce que je vois, les commentaires conditionnels ont encore de beaux jours devant eux ;)

jpvincent a dit le

bon tricks, qui laissent au moins le choix de targeter ou pas IE8.

c'est un poil plus compliqué qu'utiliser du JS pour détecter le support des CSS, comme le fait http://www.modernizr.com/ mais ça a le mérite d'exister, de garder intacte la séparation CSS/JS et d'être performant

bon bien sur pour que ça soit maintenable, il faut tout de même réserver ça à des situations exceptionnelles, mais c'est un outil à connaître :)
merci

Oncle Tom a dit le

On pourrait faire ça avec les media-query aussi j'imagine ?

Raphael a dit le

@Oncle Tom : je n'y ai pas pensé et je ne trouve pas de tableau des supports navigateurs à ce sujet. Je crois que seul IE ne les reconnaît toujours pas ?

Squal38 a dit le

Cela ne risque-t-il pas de faire baisser les performances sur un site à fort trafique ?

dew a dit le

Sans compter que l'on peut l'envisager en jQuery.

JackNUMBER a dit le

Intéressent, en effet. Merci de l'info !
Le CSS serait valide pour tous et ces "améliorations progressives" serait du plus pour les browsers récents.

Ericf a dit le

Bonjour,

Tout ça c'est bien joli, mais ça reste difficile à utiliser quand le client veut que sa charte graphique soit la même partout.
Pour moi par exemple qui n'ai pas la possibilité de modifier les PSD qu'on m'envoie, CSS 3 reste de la théorie, et le restera tant qu'on me demandera de travailler pour IE6, IE7 et IE8...

Ceci dit, merci pour cet article intéressant :-)

Raphael a dit le

@Ericf : c'est un débat un peu trollesque, mais "un client qui veut que sa charte graphique soit la même partout" est mal informé du média Web.
De notre côté, on a trouvé un argument qui devient de plus en plus convaincant pour les éduquer : on leur calcule le temps supplémentaire (et le coût associé) d'une compatibilité avec les navigateurs de génération n-1 et n-2.

Ericf a dit le

@Raphael : je ne pense pas que ce soit trollesque, c'est même mon quotidien... Concernant la mauvaise information, je suis d'accord, mais pour ma part je n'ai à faire qu'à des agences et non pas au client final à qui est vendue la prestation.
Quant au temps supplémentaire passé à débugger pour IE, effectivement il est conséquent et facturé.

Ladytron a dit le

C'est le souci de pas mal de d'agences ignorant le concept d'éducation du client. Si elles sont elles-même mal informées se contentent de faire des courbettes à leurs clients, ce n'est pas étonnant.
Je reste de l'avis de Raphael à ce sujet.

IED Factory a dit le

Toujours très à la pointe Raphaël et très à l'écoute... Bravo ! Les commentaires sont bien le reflet du souci permanent de trouver un bon équilibre entre les désirs (parfois irréalistes des commanditaires) et la réalité de terrain...

Cordialement. Stéphane

Oncle Tom a dit le

@Raphael : Cf. http://www.quirksmode.org/m/css.html#t021 pou... les mobiles et http://www.quirksmode.org/css/contents.html#t... pour le desktop. Ceci dit, IE n'est pas un navigateur moderne donc ça me choquerait pas de ne pas le considérer avant IE9.

Raphael a dit le

@Oncle Tom : Ah oui merci, je vais méditer là dessus :)

EDIT : mouais en fait ce n'est pas si utilisable que ça puisque ce n'est pas reconnu par IE8 (sans surprise) mais pas non-plus par Fx 3.0 et Konqueror 3.5.7

Nico3333fr a dit le

Celui que j'utilise souvent, c'est celui-là :
#bandeau{
// pour tout le monde, IE 6 compris
}
body > #bandeau{
// pour tout le monde, sauf IE 6
}

L'exemple classique :
body > #bandeau{
position: fixed; /* salete d'IE 6 ... gere pas fixed */
}

cahnory a dit le

@Nico3333fr : Je dit ça sans avoir testé la compatibilité mais ne serait-il pas, pour le coup, plus tout terrain de faire plutôt :
html > body #bandeau { }

Qui serait plus proche du ciblage #bandeau (élément ayant pour id bandeau présent n'importe où sur la page).
Je rappel que je n'ai pas testé, je réagis juste sur le vif :)

cahnory a dit le

@Nico3333fr : Je dit ça sans avoir testé la compatibilité mais ne serait-il pas, pour le coup, plus tout terrain de faire plutôt :
html > body #bandeau { }

Qui serait plus proche du ciblage #bandeau (élément ayant pour id bandeau présent n'importe où sur la page).
Je rappel que je n'ai pas testé, je réagis juste sur le vif :)

Nico3333fr a dit le

Cahnory : ça doit marcher aussi ! :)

Nico3333fr a dit le

Autre méthode pour le progressive enhancement : faire un site de base (pour IE) calquée sur une résolution plutôt basse, et utiliser les média-queries pour adapter le site aux résolutions supérieures.

Raphael a dit le

@Nico3333fr : oui sur le principe (aussi parce que j'adore les MQ), mais en pratique, proposer un site de 800px de large à IE8 est un peu frustrant de nos jours...

tenev911 a dit le

Pour information, PIE CSS permet le support de quelques éléments CSS3 de base dans IE.

Sinon, un autre hack CSS pour internet explorer (pas du tout valide W3C) :

color:blue; /* Normal */
color:green\9; /* IE8 et moins */
*color:red; /* IE7 et moins */
_color:yellow; /* IE6 */

Raphael a dit le

@tenev911 : oui tout à fait, les outils JavaScript pour aider IE sont très nombreux : http://www.alsacreations.com/astuce/lire/1076...
Mais ce n'est pas tout à fait la question ici.

Sinon, pour les Hacks tels que *propriété ou _propriétés, ce sont les seuls à peu près viables. Les autres sont trop risqués car trop empiriques et non pérennes.

Chok71 a dit le

Bonjour,
Je suis d'accord avec ericf, je pense aussi qu'un site doit pouvoir être identique sur tous les navigateurs du marché, et que chaque internautes doit pouvoir avoir la même expérience peu importe son navigateur (ça fait partie de l'accessibilité non ?).
Une dégradation élégante pour IE6 à la limite mais pas IE7 / IE8 car ils sont encore très utilisés.

Melli a dit le

Je sais que beaucoup d'entre vous travaille à un niveau ou il est impossible d'exclure IE du cahier des charges. Pour ma part, je trouve la politique de Microsoft tout simplement odieuse et partant du principe qu'il est extrèmement simple pour un utilisateur de changer de navigateur, j'ai pris la décision d'ignorer purement et simplement IE, même dans sa version 9. Ça n'a absolument aucun intérêt, que ce soit pour les designers ou les utilisateurs. Que IE meure dans la honte, j'irai danser sur sa tombe (non, en fait même pas...).

Raphael a dit le

@Chok71 : je dis simplement que "avoir la même expérience utilisateur" et "avoir un site identique" sont deux choses différentes, il n'y a qu'à voir l'exemple de Twitter : pas d'arrondis sur IE6 / IE7 : est-ce un problème ? Non, aucunement.

C'est tout l'intérêt de l'amélioration progressive : on conserve l'expérience utilisateur mais de là à faire des choses au pixel près... faut être de plus en plus motivé.

PS : aucun rapport avec l'accessibilité qui ne cible que les personnes avec déficiences, pas la compatibilité des navigateurs.

Jep a dit le

Je me permet de chipoter hein, mais :lang() est un sélecteur CSS2 (pas CSS3) ;)

Raphael a dit le

@Jep : ah oui.
Plus précisément, elle apparaît en CSS2 : http://www.w3.org/TR/CSS2/selector.html#lang
... Et est redéfinie en CSS3 : http://www.w3.org/TR/css3-selectors/#lang-pse...

rik24d a dit le

Bon, je vais être désagréable (comme d'habitude) mais je trouve la proposition d'utiliser :root (ou tout autre sélecteur CSS3) pour déterminer le support d'autres propriétés complètement contre-productive. C'est presque aussi mauvais que la détection de user agent.

Cela revient à dire "c'est une BMW donc elle c'est une propulsion" (j'ai pas d'exemples plus intelligents en tête). C'est souvent vrai mais pas tout le temps.

Par exemple, un cas cité pose déjà problème. Opera supporte :root mais pas flex box. La seule manière de prévoir l'avenir, c'est détection de fonctionnalité (comme Modernizr) ou utiliser plusieurs propriétés. Du genre on commence par un background: url() suivi d'un background: linear-gradient(). Là, le navigateur se débrouillera pour comprendre ce qu'il sait comprendre et on ne fera aucune hypothèse sur le support.

AkaiKen a dit le

J'aime beaucoup Modernizr (je l'ai utilisé, mais pour vérifier la gestion des balises audio), mais quid des gens ayant désactivé le javascript ?
Ne vaut-il mieux pas utiliser les border-radius etc, sans vérifier (au besoin en utilisant justement les tricks à base de '>' etc.), puisque ce ne sera pas compris du tout par IE (par exemple), et pas "mal compris" ? Le résultat est le même.

Raphael a dit le

@rik24d : tu as raison, je me suis sans doute emporté sans préciser qu'il s'agissait d'employer ces astuces avec pincettes et en complète connaissance de cause.

Ce qui me gêne dans Modernizr, c'est son inutile complexité (tester une 50aine de fonctionnalités pour se servir de trois d'entre-elles, c'est moyen) et, accessoirement, le passage obligé par JavaScript, comme le dit AkaiKen.

rik24d a dit le

Je suis d'accord pour dire que l'obligation de JS est dommage pour Modernizr mais on peut passer outre en prévoyant de n'utiliser Modernizr que pour ajouter. Donc prévoir la CSS pour qu'elle "fonctionne" sans JS et ensuite utiliser les classes qu'ajoute Modernizr.

Pour le problème de tester 50 fonctionnalités, Modernizr 2 (actuellement en beta) permet de choisir quels tests on veut effectuer : http://modernizr.github.com/Modernizr/2.0-bet...

AkaiKen a dit le

rik24d > c'est une bonne idée, pour Modernizr 2, mais perso je n'aurais pas du tout fait comme ça. J'aurais plutôt laissé tous les tests dans le fichier js, et c'est l'appel à Modernizr qui aurait déterminé quels tests faire.

Ensuite "Donc prévoir la CSS pour qu'elle "fonctionne" sans JS et ensuite utiliser les classes qu'ajoute Modernizr.", oui, trois fois oui. Mais là encore ça signifie faire une CSS basique, sans fioritures CSS3 etc ?

rik24d a dit le

AkaiKen > Peut-être que ta solution est plus intéressante mais ça implique plus de téléchargement et de parsing pour rien dans beaucoup de cas. Les deux solutions ont avantage et inconvénients.

Pour CSS sans JS, pas besoin d'une CSS basique, il suffit juste de bien choisir les sélecteurs. Exemple:
#foo {
background: url();
}
.multiple-backgrounds #foo {
background: url(), url(), url();
}

Raphael a dit le

@rik24d : "Modernizr 2 (actuellement en beta) permet de choisir quels tests on veut effectuer" -> ça c'est vraiment sympa !

hmalaud a dit le

A noter pour simuler les sélecteurs css avancés sur les navigateurs ne les supportant pas la librairie selectivizr (http://selectivizr.com/) ; petit bémol, elle n'est pas autonome mais est compatible avec moult librairies ultra répandues aujourd'hui.

Raphael a dit le

@hmalaud : oui.
Comme je l'ai répondu à @tenev911, les outils JavaScript pour aider IE sont très nombreux : http://www.alsacreations.com/astuce/lire/1076-utiliser-css3-aujourdhui-outils-ressources.html Mais ce n'est pas tout à fait la question ici. ;)

Victor BRITO a dit le

@Raphael : Konqueror 4.5.1 reconnaît les media queries (je viens de le vérifier). Cela dit, je n'ai pas encore croisé d'agences Web ou de clients demandant la compatibilité avec Konqueror. ;) Quant à Firefox 3.0, je me demande si beaucoup en tiennent encore compte (vu l'évolution plus rapide des parts de marchés entre versions de Firefox qu'entre versions d'IE, à titre de comparaison).

Pour le reste, je ne suis pas emballé par l'idée d'utiliser des pseudo-classes comme :root ou :lang, surtout s'il s'agit de cibler un panel de navigateurs à l'exclusion de certaines versions d'IE. Bref, je préfère encore recourir aux commentaires conditionnels et ne pas servir les correctifs à ceux qui n'en ont pas besoin.

Cela dit, je ne remets pas en cause la qualité de l'article.

Nico3333fr a dit le

@Raphael : en même temps, faire ch... un utilisateur d'IE n'est pas pour me déplaire (mode cynique on).

(mode cynique reloaded)
On peut raisonnablement penser que vu qu'il utilise un navigateur antédiluvien, il a un écran antédiluvien, donc on adapte la résolution du site à son écran. Et encore, si on poussait le raisonnement, on lui afficherait en 640x480, donc qu'ils ne se plaignent pas s'ils ont du 800x600, c'est déjà un immense cadeau que nous leur faisons.

Mais pourquoi est-il si méchant ? PARCE QUUUEEEEEEEE !

Raphael a dit le

@Nico3333fr : "On peut raisonnablement penser que vu qu'il utilise un navigateur antédiluvien" -> considérer que IE8 est antédiluvien est un peu extrémiste, non ? A ma connaissance c'est la toute dernière version officielle à la date d'aujourd'hui ;)

Skoua a dit le

@Nico3333fr : Perso je préfère encore m'embêter à faire fonctionner mon site dans IE7+ avec des commentaires conditionnels que refaire une maquette en 800px de large pour IE, c'est pas forcément un gain de temps. :)

Sinon, à quand un en-tête X-IE-Force-Update envoyable par le serveur pour forcer la mise à jour de Internet Explorer ? :o

Riku Asakura a dit le

Très bien tout ça, une brochette de solutions, on a plus qu'à piocher en fonction de ses besoins ;)
Merci

fvsch a dit le

«Je suis d'accord avec ericf, je pense aussi qu'un site doit pouvoir être identique sur tous les navigateurs du marché, et que chaque internautes doit pouvoir avoir la même expérience peu importe son navigateur (ça fait partie de l'accessibilité non ?).»

Non, ça ne fait pas partie de l'accessibilité.
Et Éric disait que ses clients (des agences web) exigent de l’identique partout et ne lui laissent pas de marge de manœuvre pour faire de l’amélioration progressive. Rien de plus.

Flowermountain a dit le

Je trouve que Modernizr c'est très bien moi... Et j'avoue que je pensais que 4Ko de javascript étaient négligeables.

Perso je préfère l'approche par propriété CSS que par navigateur. Il n'y a pas que des histoires de IE/pas IE, ça peut être intéressant de cibler tous les navigateurs qui ne supportent pas une propriété pour proposer autre chose à la place.

Nico3333fr a dit le

@Raphael, @Skoua : je sais bien, mais un peu de mauvaise foi pour la bonne cause, ça ne fait pas de mal. :)

@fvsch : tous mes clients me demandent la même chose, j'ai déjà du mal à leur faire comprendre que certains effets Jquery n'ont pas un rendu optimal sur IE et qu'on n'y peut rien. :-\

marc.suisse a dit le

Bonjour à tous,

Si je comprends bien, on pourrait considérer les sélecteurs css avancé tels que root et lang comme des "commentaires conditionnels ?

Je sais bien que les commentaires conditionnels sont l'apanage de IE, mais on peut ( pour faciliter la compréhension ) dire que le fonctionnement est pareil, seulement les navigateurs supportant le css3 pourront lire ce qui commence par root et lang.

Ou cela n'a rien à voir ?

Felipe a dit le

Utiliser le pseudo-sélecteur :root permet de cibler les navigateurs qui comprennent ce sélecteur (Mr de Lapalisse serait fier de moi :) ) à condition que CSS soit activé.

1/ Les CC étant des commentaires HTML ils fonctionnent eux dans tous les cas.
2/ Il reste à savoir si le support de :root signifie forcément support de (vendor-)border-radius et autres propriétés CSS3. Pas de souci dans les navigateurs qui sortent en 2011 mais si tu supportes Fx 3.0 ou 3.5, Op 9.8 ou que sais-je d'autre il faut tester :)

Chok71 a dit le

@fvsch : Je vois pas pourquoi un site serait joli sur certains navigateurs et pas d'autres. Ça fait pas pro du tout, surtout que IE représente encore la moitié des internautes.

Chok71 a dit le

Suffit de regarder le site qui a servi d'exemple au livre "CSS3 pour les designers", en comparant le formulaire sur Firefox et sur IE c'est quand même abusé la différence... C'est pourtant, pour l'auteur, un bon exemple de dégradation élégante -_-'.
Un telle différence pour une histoire de gagner un peu plus de temps c'est pas justifiable selon moi.

Chok71 a dit le

L'adresse du site que j'ai oublié : http://css3exp.com/moon/

Nigel a dit le

Chok71 : En effet, il y a une perte importante en terme d'utilisabilité sous IE. Les contrastes sont particulièrement mauvais.

Le principe de dégradation (élégante ou pas), n'a aucun sens en ergonomie. Chacun doit pouvoir obtenir le même résultat quelque soit l'outil employé, le handicap, etc... Tant que cela reste réalisable.
Cela demande parfois plus de temps de conception, peut-être. C'est un choix un prendre.

Etudier une dégradation élégante et la maitriser demande de toutes façons un temps de vérification supplémentaire, est-ce vraiment rentable ? A mon avis, c'est du cas par cas.

pomeh a dit le

La version 2.0 de modernizr (actuellement en beta) permet de construire sa propre version de modernizr en choisissant que les tests dont on a besoin. Ca évite d'avoir environ 800 classes sur la balise <html> et ça permet de ne pas avoir de code Javascript qui ne s'exécute pour rien sur notre page donc des performances un peu meilleures :)

C'est par ici que ça se passe: http://modernizr.github.com/Modernizr/2.0-bet... (il est possible que le lien devienne obsolète sous peu car c'est un emplacement spécifique pour la beta...)