Envoyer un mail à l’auteur
xavier at ultra-fluide.com

Ressources

CSS et les obliques.

Sommaire

Cet article a pour origine notre participation à un concours de code (dont nous sommes fier d'avoir été le lauréat) pour lequel il s'agissait de reproduire, sans image, cette oeuvre de Mondrian (ce lien ouvre une fenêtre popup). Les curieux trouveront sur ces pages le règlement et le résultat de ce concours.

Le challenge était donc de représenter des segments obliques séparant des aplats de couleurs par du code web compatible avec les principaux navigateurs. L'une des solutions, la plus simple probablement, consiste à exploiter les bordures d'éléments blocks CSS.

Principe de tracé d'oblique

Nous présentons et exploitons dans cet article la ligne oblique apparaissant à la rencontre des bordures encadrant les éléments blocks CSS. Un élément block est un rectangle, et ses bords lorsqu'ils sont tracés se rejoignent sur une intersection oblique. En jouant sur la taille du rectangle, les épaisseurs des différents bords ainsi que leurs couleurs, un nombre infini d'effets peuvent être obtenus.

Lorsque l'épaisseur des bords horizontaux et verticaux est identique l'oblique est à 45 degrés. L'élément choisi pour notre exemple est l'élément paragraphe <p> mais n'importe quel élément acceptant des bordures et ayant implicitement ou explicitement la propriété {display : block} conviendra.

Voici un premier élément block avec des bords de 60 pixels d'épaisseur.
élément block
<style type="text/css">
  div {
  border:60px solid;
  border-color:#E8314D #FA9AA6
  }
</style>
<body><div>élément block</div></body>
Lorsque l'élément est vide, et que les bords se touchent.
<style type="text/css">
  #a {
  width:0;height:0;
  border:60px solid;
  border-color:#E8314D #FA9AA6
  }
</style>
<body>
  <div id="a" ><div></div></div>
</body>
En modifiant l'ordre des couleurs.
<style type="text/css">
  #a {
  width:0;height:0;
  border:60px solid;
  border-color:#E8314D #E8314D
  #FA9AA6 #FA9AA6;
  }
</style>
<body>
  <div id="a" ><div></div></div>
</body>

Variations

Partant des exemples précédents, il est possible d'obtenir des segments d'inclinaisons variables en jouant sur le rapport des épaisseurs des bordures. Ensuite la superposition de segment permet d'atteindre n'importe quelle forme géométrique.

La bordure du bas a une épaisseur nulle.
<style type="text/css">
  #a {
  width:0;height:0;
  border:60px solid;
  border-bottom:none;
  border-color:#E8314D #FA9AA6
  }
</style>
<body><div id="a" ><div></div></div></body>
Les bordures du bas et de droite ont une épaisseur nulle.
<style type="text/css">
  #a {
  width:0;height:0;
  border:60px solid;
  border-bottom:none;border-right:none;
  border-color:#E8314D #FA9AA6
  }
</style>
<body><div id="a"><div></div></div></body>
Les bordures du bas et de droite ont une épaisseur nulle. Le bord gauche est 2 fois plus épais que le bord haut : le segment se rapproche de l'horizontale.
<style type="text/css">
  #a {
  width:0;height:0;
  border:60px solid;
  border-left-width:120px;
  border-bottom:none;border-right:none;
  border-color:#E8314D #FA9AA6
  }
</style>
<body><div id="a"><div></div></div></body>
Les bordures du bas et de droite ont une épaisseur nulle. Le bord haut est 2 fois plus épais que le bord gauche : le segment se rapproche de la verticale.
<style type="text/css">
  #a {
  width:0;height:0;
  border:60px solid;
  border-top-width:120px;
  border-bottom:none;border-right:none;
  border-color:#E8314D #FA9AA6
  }
</style>
<body><div id="a"><div></div></div></body>
En superposant 2 blocks et en utilisant la propriété transparent pour la couleur de bordure on peut obtenir le tracé d'un filet oblique.
Malheureusement, IE ne reconnaît pas la propriété transparent pour une bordure (la propriété transparent a été introduite avec la norme CSS 2 en 1998). Pour IE la valeur transparent est traduite par la couleur noire, cet exemple ne fonctionne donc pas sous IE.
<style type="text/css">
 #a, #b {
 position:absolute;
 width:0;height:0;margin:0;padding0;
 }
 #a {
 top:0px;
 border:120px solid;border-top-width:180px;
 border-color:transparent;
 border-left-color:#E8314D
 }
 #b {
 top:3px;
 border:118px solid;border-top-width:177px;
 border-color:transparent;
 border-left-color:#FFFFFF
 } 
 #a, #b {border-bottom:none;border-right:none}
</style>
<body><div id="a"></div><div id="b"></div></body>
Une publicité pour Renault en HTML + CSS ? (Ne fonctionne pas sous IE, voir l'explication donnée à l'exemple précédent)
<style type="text/css">
 #a, #c, #e, #g, #b, #d, #f, #h {
 position:absolute;
 width:0;height:0;top:0;left:0;
 border:70px solid;border-top-width:105px;
}
 #e, #f, #g, #h {
 border:60px solid;border-top-width:90px
 }
 #a, #d, #e, #h {border-left:none}
 #b, #c, #f, #g {border-right:none}
 #a, #c, #e, #g, #b, #d, #f, #h {
 border-bottom:none;border-color:transparent
 }
 #c, #d {top:30px}
 #g, #h {top:45px}
 #a {border-top-color:#E8314D}
 #b {left:40px;border-top-color:#E8314D}
 #c {border-left-color:#E8314D} 
 #d {left:40px;border-right-color:#FFFFFF } 
 #e {left:-15px;border-top-color:#FFFFFF} 
 #f {left:65px;border-top-color:#FFFFFF} 
 #g {left:-15px;border-left-color:#FFFFFF} 
 #h {left:65px;border-right-color:#FFFFFF}  
</style>
<body>
  <div id="a"></div><div id="b"></div>
  <div id="c"></div><div id="d"></div>
  <div id="e"></div><div id="f"></div>
  <div id="g"></div><div id="h"></div>
</body>

Code CSS pour la représentation du tableau de Mondrian

Modèle à représenter (ce lien ouvre une fenêtre popup).

Les bordures d'éléments block conviennent bien pour représenter ce Mondrian : les aplats de couleur sont simplement délimités entre eux par des obliques à 45 degrés.

Un élément block permet de tracer l'intersection de 2 obliques. Il suffit donc de 6 éléments blocks (id de a à f dans le code ci-dessous). L'élément id=z sert de cadre à l'ensemble. Enfin l'ajout d'un dernier élément block ne présentant aucun effet visuel permet d'obtenir la compatibilité avec Internet Explorer (bug apparaissant sur les éléments vides, peut également être corrigé avec {font-size:0}).

Pour ce concours il était en plus demandé d'optimiser le code, c'est à dire de minimiser le nombre de caractères utilisés. Nous avons donc retiré l'ensemble des balises n'étant pas strictement indispensables (<html>, <head>, <title>...).

<style>
  #z{overflow:hidden;height:490px;width:615px;margin-left:-155px}
  div{position:absolute}
  #a{border:230px solid;border-color:#f00 #f00 #000 #ffd;top:40px}
  #b{border:140px solid;border-color:#ffd #f00 #f00 #ff0;top:-370px;
       left:-90px}
  #c{border:160px solid;border-color:#f00 #00a #ffd #f00;top:140px;
       left:20px}
  #d{border:100px solid;border-color:#00a #00a #dda #ffd}
  #e{border:80px solid;border-color:#f00 #ffd #000 #000;top:-100px;
       left:-260px}
  #f{border:120px solid;border-color:#ffd #ffd #f00 #f00;top:-480px}
</style>
<div id="z"><div id="a"><div id="b"><div id="c">
<div id="d"><div id="e"><div id="f"><div>

Optimisation du poids du code par factorisation javascript

Afin de réduire encore le nombre de caractères utiles au codage de ce "Mondrian", nous avons cherché à factoriser ce code : en effet dans le CSS comme dans le HTML il est visible qu'une structure de code se répète à chaque élément div. Chaque répétition diffère néanmoins d'une autre de par les valeurs numériques désignant le positionnement, les couleurs et la taille de la div.

Nous avons donc définit une fonction javascript qui pose la structure commune, et accepte les paramètres numériques nécessaires. Ainsi la structure répétée en HTML et CSS n'est écrite qu'une fois en javascript lors de la définition de la fonction (function f(w,t,r,b,l,y,x)).
Ensuite la répétition s'obtient en appelant la fonction autant de fois que nécessaire (7 fois dans notre exemple, pour les 7 div "identiques"). La répétition de l'appel à la fonction (16 caractères environ) est beaucoup plus économique que la répétition de la structure complète (plus de 70 caractères).
La div qui sert de cadre est atypique, elle donc écrite indépendamment.

En définitive voici le code que nous avons utilisé :

<script>
  r='f00';n='000';c='ffd';b='00a';p='position:absolute;';
  function f(w,t,r,b,l,y,x){
     return '<div style="'+p+'border:'+w+
     '0px solid;border-color:#'+t+' #'+r+' #'+b+' #'+l+';top:'+y+
     '0;left:'+x+'0">'
  }
  document.write('<div style="overflow:hidden;'+p+
  'height:490;width:615;margin-left:-155">'
  +f(23,r,r,n,c,4)+f(14,c,r,r,'ff0',-37,-9)+f(16,r,b,c,r,14,2)
  +f(10,b,b,'dda',c)+f(8,r,c,n,n,-10,-26)+f(12,c,c,r,r,-48)+f())
</script>

Exemples présentés par d'autres auteurs

De multiples formes géométriques :
http://www.infimum.dk/HTML/slantinfo.html

Un pavage d'hexagones en guise de menu chez Tantek :
http://tantek.com/map.html

Un peu d'animation dans tout ça (CSS + javascript) :
http://www.infimum.dk/HTML/rotatingBox.html


Agence de communication Ultra-Fluide : 01 47 70 23 32 - contact at ultra-fluide.com - 44 rue Richer 75009 Paris.