Le CSS (pour Cascading Style Sheets) est un langage de "programmation" utilisé pour décrire l'apparence d'une page écrite dans un langage markup comme le HTML (d'autres langages, tels le SVG peuvent aussi avoir leurs feuilles de style).
Tout d'abord, faisons la chasse à un préjugé : « Le CSS, ce n'est pas simple. »
Dans la mesure où le CSS ne permet pas de faire d'algorithmes, il est souvent perçu comme un langage facile à utiliser, et donc un langage facile. Mais il s'agit de deux choses différentes : n'importe qui peut écrire une feuille de style, mais écrire la feuille de style répondant à la charte graphique fournie par votre graphiste nécessite une connaissance des propriétés et du fonctionnement de CSS. Et ça n'est pas si simple que ça.
CSS, c'est :
Bien évidemment, ce n'est pas parce qu'une infinité de sélecteurs peuvent exister pour un élément qu'il faut tous les utiliser, bien au contraire, mais on retrouve fréquemment dans nos applications des erreurs dues aux propriétés mentionnées ci-dessus :
Dans nos projets, on écrit beaucoup de CSS, probablement trop, sans trop comprendre comment l'utiliser.
Ce premier module couvrira les bases du CSS : à quoi ça ressemble, comment il s'ajoute dans une application, sur une page, à quoi il peut s'appliquer. Nous définirons ce qu'est un sélecteur. Nous étudierons la cascade des styles pour déterminer quel sélecteur s'applique à quel élément du DOM.
Des liens intéressants à garder en marque-page seront fournis tout du long, n'hésitez pas à les conserver.
Un premier lien : l'index CSS du CSS working group du W3C qui liste toutes les propriétés, leurs valeurs, la grammaire utilisée pour appeler leur valeur (moins utile), les fonctions, les règles @ et les sélecteurs du langage qui sont référencés dans une spécification CSS du W3C. Et ça en fait beaucoup.
Le CSS, ça ressemble à ça :
Ici, on a décrit la classe CSS appelée "quality-box", qui a pour propriétés une largeur faisant 20% de son conteneur parent auquel on retirera 20 pixels, des marges de 10 pixels de chaque côté, et un affichage de type inline-block, à savoir gardant les propriétés de l'affichage block tout en s'affichant à la droite de l'élément inline qui le précède (là où un élément block se positionnerait en dessous).
Ces propriétés seront étudiées dans un module ultérieur.
Comme ça :
Sur l'élément HTML div, on ajoute l'attribut class et la valeur vaut la ou les classes qu'on souhaite appliquer. A noter : une classe commence par un point dans le fichier de style, mais on ajoute son nom sans le point dans l'attribut class.
Dans le cas où vous travaillez avec React en JSX, class étant un mot JS réservé, l'attribut à utiliser est className.
Si vous utilisez des CSS modules, la valeur de l'attribut className vaut le nom que vous avez choisi quand vous avez importé votre CSS. Ce dernier point sera traité dans la formation CSS avancé, activité CSS Modules.
Il est possible d'ajouter une classe sur la majorité des éléments du DOM ayant une représentation graphique (n'allez pas mettre de classe sur la balise script s'il vous plait).
Ainsi, l'ensemble des balises HTML est concerné, mais aussi SVG.
Petit rappel : le HTML a été enrichi à l'occasion d'HTML5 (vous en avez probablement entendu parler) de balises appelées balises sémantiques. Là où des balises comme div ou span sont agnostiques (on y met le contenu qu'on veut), de nouvelles balises plus précises sont nées telles que :
header / nav / article / aside / footer
En passant : si div et span sont agnostiques quant à leur contenu, il existe une règle méconnue : on ne met pas de div dans un span.
Les propriétés CSS des feuilles de style des navigateurs traduisent ce fait : les div sont en display: block, les span en display: inline par défaut.
N'allez donc pas mettre un bloc dans une balise faite pour du texte s'il vous plait.
Les styles CSS (la définition des classes et leurs propriétés associées) peuvent exister à de multiples endroits :
Il est fortement déconseillé d'utiliser des styles embedded ou inline !
En effet, cela cause des problèmes de maintenabilité (avec du code déporté sur les pages), de compréhension (les styles inline sont prioritaires, on le verra plus tard dans ce module).
Néanmoins, dans certains cas très spécifiques, il est possible que vous ayez à utiliser des styles inline : notamment dans le cas de composants JS où le style appliqué dépend directement de la valeur d'une variable JS (il est possible sinon d'utiliser une custom property cependant, mais cela fera partie du module CSS avancé, sans compter que l'utilisation de custom properties est conditionnée à leur compatibilité avec le navigateur, par exemple, pas IE11).
On peut voir ici une balise HTML style dans lequel le code CSS est ajouté. Petit rappel : n'utilisez JAMAIS de CSS embedded.
On peut voir l'attribut style sur la balise body. A éviter également, à n'utiliser que si on a des styles variables sans la possibilité d'utiliser des custom properties CSS.
et dans un fichier appelé ici mes-styles.css :
Le principe est de mettre toutes les définitions de style au sein de feuilles de style, des fichiers séparés, qui sont importés dans la page par l'utilisation de la balise link avec l'attribut rel valant stylesheet (la balise link sert à importer des fichiers externes, l'attribut rel à définir la relation que ce fichier aura avec la page, et la valeur stylesheet à mentionner que le fichier est un fichier de style).
Enfin, il est possible d'avoir des feuilles de style conditionnelles pour les version d'Internet Explorer < 10.
Cela permet de charger des styles supplémentaires dans le cas où l'on répond aux conditions fournies. On peut importer une feuille de style de façon conditionnelle de cette façon :
notez le commentaire conditionnel:
Un sélecteur CSS, c'est la chaîne permettant de cibler les éléments du DOM qui seront concernés par les styles définis.
le sélecteur est « ul > li.title »
Il signifie qu'on ciblera uniquement les éléments li qui sont les enfants directs d'un élément ul, et qui ont l'attribut class contenant la valeur title.
Motif | Description |
---|---|
* | cible n'importe quel élément de la page. Dans les faits on s'en sert pour définir les valeurs par défaut appliquées sur la page, telles la couleur de base et/ou la taille de base de la police. |
B | correspond à une balise du DOM (par exemple div ou span ou ul ou table ou svg). Sans plus de précision, toutes ces balises seront concernées par les styles associés. |
.warning | Ici on définit une classe CSS, du nom de warning. La définition d'une classe CSS commence par un point. Son utilisation sur la page se fait sans le point (par exemple, on aurait ici <div class="warning">. Tous les éléments du DOM dont l'attribut class contient le nom de la classe sont ciblés. |
#myid | Ici, on cible un identifiant donné. Tout élément du DOM peut se voir attribuer un identifiant, sous la forme <div id="myId">. Dans la feuille de style, on peut cibler l'élément ayant un identifiant donné en le préfixant de #. Petit rappel : un identifiant doit être unique sur l'intégralité de la page. |
Pour toute la suite, on utilisera E (pour Elément) comme base sur laquelle on applique les différentes variantes de sélecteurs : il s'agit ici d'une facilité d'écriture, et dans toute la suite, E peut être remplacé par n'importe quel sélecteur. Les types de sélecteurs décrits peuvent s'appliquer à tout sélecteur, pas uniquement aux éléments du DOM.
Si vous lisez E:first-child, cela peut vouloir dire "div:first-child", comme cela pourrait être ".warning:first-child" (qui veut dire un élément possédant l'attribut class ayant pour valeur "warning" et qui est le premier enfant de son parent) ou "ul.ma-liste > li.mon-item:first-child". Si une balise doit être utilisée explicitement pour la règle, cela sera mentionné dans la description (par exemple pour :nth-of-type).
Il est possible de cibler des éléments en fonction des attributs existant sur la balise du DOM, voire de leurs valeurs
Motif | Description | Exemples |
---|---|---|
E[foo] | Un élément E du DOM ayant l'attribut foo qu'il ait une valeur ou non. | <div data-focus="test"> ou <div data-focus> seront ciblés par div[data-focus] |
E[foo="bar"] | Un élément E du DOM dont l'attribut foo a pour valeur bar. | <div data-focus="test"> sera ciblé par div[data-focus="test"] |
E[foo~="bar"] | Un élément E du DOM dont l'attribut foo est une liste de valeurs séparées par un espace, dont l'une a pour valeur bar. | <div data-focus="test"> et <div data-focus="test item "> seront ciblés par div[data-focus~="test"] |
E[foo^="bar"] | Un élément E du DOM dont l'attribut foo commence par bar. | <div data-focus="testdecomposant"> et <div data-focus="test"> seront ciblés par div[data-focus^="test"] |
E[foo$="bar"] | Un élément E du DOM dont l'attribut foo termine par bar. | <div data-focus="pasuntest"> et <div data-focus="test"> seront ciblés par div[data-focus$="test"] |
E[foo*="bar"] | Un élément E du DOM dont l'attribut foo contient bar. | <div data-focus="pasuntest">, <div data-focus="testdecomposant">, <div data-focus="ceciestuntestdecomposant"> et <div data-focus="test"> seront ciblés par div[data-focus*="test"] |
E[foo|="bar"] | Un élément E du DOM dont l'attribut foo vaut bar ou commence par bar suivi d'un tiret | <div data-focus="test"> et <div data-focus="test-composant"> seront ciblés par div[data-focus|="test"] mais pas <div data-focus="test test2"> ni <div data-focus="testcomposant"> |
Ne sont pas des classes. Il s'agit d'une syntaxe permettant de cibler certains éléments en fonction de caractéristiques qui ne peuvent pas être déduites du DOM comme leur état ou leur "ordre". Cela permet d'ajouter plus de précision sur les sélecteurs.
Motif | Description |
---|---|
:root |
Permet de cibler la racine du document. S'utilise uniquement sous la forme :root
{ /* styles */ } sans spécifier d'élément, la racine étant la racine.
On s'en sert souvent pour donner les valeurs par défaut des custom
properties (que l'on verra ultérieurement).
|
Motif | Description |
---|---|
E:first-child | Permet de cibler un élément E qui est le premier enfant de son parent, tous types confondus. |
E:nth-child(n) | Permet de cibler un élément E qui est le n-ième enfant de son parent, tous types confondus. n est un entier. |
E:nth-last-child(n) | Permet de cibler un élément E qui est le n-ième enfant de son parent en partant de la fin, tous types confondus. n est un entier. |
E:last-child | Permet de cibler un élément E qui est le dernier enfant de son parent, tous types confondus. |
E:only-child | Permet de cibler un élément E s'il est l'enfant unique de son parent, tous types confondus. |
Motif | Description |
---|---|
E:first-of-type | Permet de cibler un élément E qui est le premier enfant de son parent, pour le type fourni (E doit contenir une balise à laquelle :first-of-type s'applique). |
E:nth-of-type(n) | Permet de cibler un élément E qui est le n-ième enfant de son parent, pour le type fourni (E doit contenir une balise à laquelle :nth-of-type s'applique). n est un entier. |
E:nth-last-of-type(n) | Permet de cibler un élément E qui est le n-ième enfant de son parent en partant de la fin, pour le type fourni (E doit contenir une balise à laquelle :nth-last-of-type s'applique). n est un entier. |
E:last-of-type | Permet de cibler un élément E qui est le dernier enfant de son parent, pour le type fourni (E doit contenir une balise à laquelle :last-of-type s'applique). |
E:only-of-type | Permet de cibler un élément E s'il est l'enfant unique de son parent, pour le type fourni (E doit contenir une balise à laquelle :only-of-type s'applique). |
Comme on peut le voir, on a des instructions très proches, avec une différence qui est le "type".
Si on utilise la version "-child", on comptera tous les enfants.
Si on utilise la version "-of-type", on comptera uniquement les enfants du type fourni avant la pseudo-classe.
Dans les deux cas, si l'enfant correspondant à l'indication est du type qu'on a fourni avant la pseudo-classe, le style sera appliqué, sinon il ne le sera pas.
Motif | Description |
---|---|
E:empty | Permet de cibler un élément E qui n'a aucun enfant ni contenu. |
E:link | Permet de cibler un élément E qui est un lien dont la cible n'a pas encore été visitée. |
E:visited | Permet de cibler un élément E qui est un lien dont la cible a été visitée. |
E:active | Permet de cibler un élément E qui est actif (généralement, sur lequel on clique). |
E:hover | Permet de cibler un élément E au-dessus duquel le pointeur flotte. |
E:focus | Permet de cibler un élément E qui "ciblé" (typiquement un champ de saisie dans lequel on a cliqué). |
Motif | Description |
---|---|
E:target | Permet de cibler un élément E qui est la cible d'une URL (par exemple une ancre). |
E:lang(fr) | Permet de cibler un élément E pour le langage spécifié (l'attribut lang="/* la langue */" peut être ajouté à des éléments HTML). |
E:enabled | Permet de cibler un élément E qui n'est pas désactivé (sert surtout en relation avec la pseudo-classe suivante). |
E:disabled | Permet de cibler un élément E qui est désactivé (si on a un input qui ne doit pas être actif / qui n'est actif que dans certains états de la page, on peut lui ajouter l'attribut disabled, et cette pseudo-classe permet de le cibler). |
E:checked | Permet de cibler un élément E qui est coché (radio-bouton ou checkbox). |
E:not(s) | Permet de cibler un élément qui ne correspond pas au sélecteur s (s est un sélecteur écrit sans guillemets l'encadrant). |
Les pseudo-éléments offrent accès à de l'information ou de contenu qui n'est pas directement accessible par le DOM; Par exemple, on pourra ajouter un élément non présent dans le DOM avec ::before ou ::after (les deux pseudo-éléments les plus importants car permettant de faire beaucoup, beaucoup de choses).
Motif | Description |
---|---|
E::first-line | Permet de cibler la première ligne d'un texte dans l'élément E. |
E::first-letter | Permet de cibler la première lettre d'un texte dans l'élément E. |
E::before | Permet de cibler du contenu généré supplémentaire situé avant les enfants de l'élément E dans le DOM. |
E::after | Permet de cibler du contenu généré supplémentaire situé après les enfants de l'élément E dans le DOM. |
::before et ::after peuvent paraître un peu vague, il est utile de comprendre ce qu'ils font pour les utiliser.
Comme on peut le voir ci-dessus, ::before et ::after permettent d'accéder à deux couches de contenu / de style supplémentaires pour un élément donné. Ils seront affichés derrière le contenu de l'élément, mais devant l'élément (la box) lui-même.
Pour que ces couches soient affichées, elles doivent avoir l'attribut CSS content avec une valeur non nulle !
Quelques exemples : https://codepen.io/c3dr0x/full/ExXMNRZ
Après avoir vu tous ces sélecteurs, reste encore à les mélanger !
Motif | Description |
---|---|
E F | Permet de cibler tout élément F descendant d'un élément E quel que soit le degré de profondeur ! |
E > F | Permet de cibler tout élément F directement enfant d'un élément E. |
E + F | Permet de cibler un unique élément F directement précédé dans le DOM d'un élément E et frère de cet élément E. |
E ~F | Permet de cibler tout élément F précédé dans le DOM d'un élément E et frère de cet élément E. |
.style1.style2 | Lorsque 2 classes CSS sont collées, on cible tout élément dont l'attribut classe contient les deux valeurs (l'ordre n'importe pas) |
On obtient des sélecteurs du genre :
Voilà pourquoi il est important de bien définir ses sélecteurs ! Mal définis, on prend le risque d'avoir des sélecteurs ciblant trop d'éléments; ou trop longs, ou difficiles à surcharger (le deuxième exemple ici est une surcharge d'un style de Focus2).
Bon, ça c'est pour vous faire peur : dans les faits, les sélecteurs ressembleront plus à :
Il est conseillé d'éviter d'avoir des sélecteurs trop complexes : généralement une classe suffit. Ces considérations seront plus développées dans le module "les préprocesseurs, et la pratique".
Nous avons vu dans l'activité précédente qu'il existe une grande quantité de sélecteurs.
Nous avons aussi vu qu'il est possible d'avoir ses styles à différents endroits : embedded dans la page, inline dans l'attribut style, ou dans une feuille de style séparée.
Enfin, il faut savoir que les navigateurs disposent de leur propre feuille de style interne (pour contenir les affichages par défaut des différents éléments) et qu'il est possible (avec certains plugins) d'ajouter une feuille de style personnelle à une page.
Dans tous ces styles, si des sélecteurs concernent un même élément, quel style a la priorité ?
Avant de commencer, il faut connaitre !important. Il s'agit d'une directive permettant de forcer l'utilisation d'une propriété donnée même si le sélecteur n'est pas prioritaire et que la même propriété est définie dans un style prioritaire. Pour l'utiliser :
Si on dispose d'un élément ayant les styles "ma-classe" et "ma-surcharge", en temps normal, on applique le style qui possède les deux déclarations. Cependant, du fait de l'utilisation de !important, c'est la couleur rouge qui apparaitra, mais le texte fera bien 24px;Il est extrêmement déconseillé d'utiliser !important. Le seul moyen de surcharger un style utilisant !important est d'ajouter un style prioritaire utilisant !important.
Bref, en utiliser un, c'est prendre le risque de les voir se multiplier et de devoir mettre des !important partout.
A spécificité égale, les styles utilisés seront (en premier ceux qui seront utilisés) :
Attention, Si un même sélecteur ou un sélecteur de même spécificité est défini plusieurs fois dans une feuille de style, le dernier (dans l'ordre de chargement des styles) l'emporte
Le sélecteurs CSS possèdent chacun une spécificité, un indicateur de précédence permettant de déterminer quel style doit s'appliquer. Les règles ci-dessous sont valides : soit entre éléments disposant tous de !important, soit entre éléments n'ayant pas la directive !important.
Si une propriété a !important, elle s'appliquera avant toute autre valeur n'en disposant pas. Si plusieurs ont la directive !important, il faudra comparer leur sélecteur comme pour le cas où il n'y a pas !important.
Sont prioritaires :
Sélecteur | A | B | C | D | Commentaire |
---|---|---|---|---|---|
* | 0 | 0 | 0 | 0 | Le sélecteur * n'a aucune spécificité |
li | 0 | 0 | 0 | 1 | Un unique élément |
li::first-line | 0 | 0 | 0 | 2 | Un unique élément et un unique pseudo-élément : ce sélecteur sera prioritaire sur le précédent |
ul li | 0 | 0 | 0 | 2 | Deux éléments : ce sélecteur a la même spécificité que le précédent : le dernier dans le fichier sera prioritaire |
ul ol+li | 0 | 0 | 0 | 3 | Trois éléments : prioritaire sur les styles précédents |
h1 + [rel="up"] | 0 | 0 | 1 | 1 | Un attribut, un élément : la présence d'un attribut donne la priorité à ce sélecteur sur tous les précédents |
Sélecteur | A | B | C | D | Commentaire |
---|---|---|---|---|---|
ul ol li.red | 0 | 0 | 1 | 3 | Une classe, trois éléments : le compteur de classes/attributs est égal au sélecteur précédent, mais il y a plus d'éléments, ce style sera prioritaire sur le précédent |
ul ol li:not(.red) | 0 | 0 | 1 | 3 | Attention : la pseudo-classe :not a une spécificité de 0. Cependant tous les sélecteurs à l'intérieur comptent pour la spécificité du sélecteur. Donc ici, une classe, 3 éléments : pareil que le précédent |
li.red.level | 0 | 0 | 2 | 1 | Deux classes, un élément. Prioritaire sur tous les précédents |
li:not(.red.level.something) | 0 | 0 | 3 | 1 | Il s'agit d'un hack commun utilisé pour surcharger des styles : on peut cumuler autant de classe qu'on le souhaite dans :not pour monter la spécificité de notre sélecteur. A connaitre, mais à éviter, de préférence |
#monId | 0 | 1 | 0 | 0 | Un identifiant, donc prioritaire à tous les précédents |
<div style="color: red;"> | 1 | 0 | 0 | 0 | Les styles inline sont prioritaires |
(identifiant ; classes/pseudo-classes/attributs ; éléments/pseudo-éléments)
Classez les sélecteurs par ordre de spécificité : le sélecteur à la plus haute spécificité sera placé en premier
CSS, ça permet de styler, mais également de positionner des boites, en résumé. Maintenant que nous avons vu comment cibler les boîtes désirées, il est temps de voir ce qui est applicable à ces boites.
La liste complète des propriétés CSS ne sera pas vue dans ce module. Il y a beaucoup trop de propriétés, et un bon paquet inutiles.
Nous allons voir dans ce module :
Le Box Model décrit le fonctionnement d'une boîte de contenu.
Comme son nom l'indique, une boîte de contenu dispose d'un contenu qui possède sa propre taille. Sans précision, la boîte ajustera sa taille à son contenu.
Il est possible de définir cependant une largeur et une hauteur à notre boîte. De plus, on peut définir d'autres propriétés qui ont un impact sur la taille finale de la boîte.
On peut enfin définir des propriétés ayant un impact sur la position de la boîte par rapport à ses voisins.
La propriété width permet de forcer la largeur de la boite. Dès qu'une valeur est fournie, le contenu s'ajuste, et s'il s'agit de texte retourne à la ligne une fois la largeur atteinte. La boite grandit alors en hauteur.
A noter, il existe des propriétés min-width, et max-width si vous souhaitez laisser à la boite la possibilité de pendre plus ou moins de place.
La propriété height permet de forcer la hauteur de la boite. Dès qu'une valeur est fournie, le contenu s'ajuste et la boite grandira en largeur.
A noter, il existe des propriétés min-height, et max-height si vous souhaitez laisser à la boite la possibilité de pendre plus ou moins de place.
Si width et height sont définis, et que le contenu est trop grand, il se produira un overflow : le contenu débordera de la place qui lui est réservée. Par défaut, l'overflow est visible. Il est possible de masquer cet overflow avec la propriété overflow (et ses déclinaisons overflow-x et overflow-y) en lui donnant la valeur hidden, ou d'afficher des barres de scroll avec la valeur scroll
La propriété padding permet de définir un écart de remplissage entre la bordure de la boîte et son contenu, ceci afin d'éviter que le contenu soit collé à la bordure. A noter : la taille finale de la boîte ajoute le padding à la largeur et à la hauteur définies plus tôt : une boîte avec une width de 1000px et un padding de 10px aura une largeur totale de 1020px si elle n'a pas de bordure.
La propriété padding est une propriété raccourcie des quatre propriétés :
qui sont utilisables séparément.
Il est possible d'utiliser la propriété padding de façons différentes :
La propriété border permet de définir la bordure de la boîte. Par défaut, elle vaut none (aucune bordure n'est dessinée).
Elle est aussi un raccourci pour tout un tas de propriétés :
qui sont déclinables pour chacun des côtés (ajouter -style, -color,ou -width pour avoir les propriétés détaillées) :
Dans les faits, on utilisera principalement la propriété raccourcie avec la syntaxe :
border: style taille couleur;
Par exemple :
border: dashed 1px black;
La taille finale de la boîte prendra en compte cette bordure (sauf avec la valeur inset) : une boîte de 1000px de width, 10px de padding et 2px de border aura une taille totale de 1024px. Border s'utilise en définissant le type de bordure souhaitée (solid, hashed, dotted, inset, groove, etc. : la liste peut-être consultée ici :
La propriété margin permet de définir un écart de remplissage entre la boîte et ses voisins. Elle n'a pas d'impact sur la taille de la boîte.
La propriété margin est une propriété raccourcie des quatre propriétés :
qui sont utilisables séparément.
Il est possible d‘ utiliser la propriété margin de façons différentes :
A noter : margin peut avoir des valeurs négatives pour faire déborder la boîte sur ses voisins.
De même, si deux boîtes consécutives ont une margin-bottom pour la première, margin-top pour la seconde, il se passe ce qu'on appelle le margin-collapsing : la plus forte des deux valeurs est conservée pour gérer l'écart entre les deux boîtes plutôt que de prendre la somme des valeurs. C'est un fonctionnement simple en apparence, mais dont les conséquences peuvent devenir ennuyeuses, surtout si on commence à jouer avec les marges négatives.
Petite démonstration interactive : https://codepen.io/klee-academy/full/GVWogL
Pour aller plus loin (facultatif, avancé) : voici une vidéo qui parle de margin collapsing (et de float, que nous aborderons plus tard) et des conséquences imprévues : https://www.youtube.com/watch?v=Y5Xa4H2wtVA (en anglais, il s'agit d'une vidéo de la BlinkOn, la conférence du moteur de rendu Blink qui montre notamment le fonctionnement interne des marges dans le navigateur ).
Le flux, c'est simplement l'ordre dans lequel les éléments du DOM s'affichent.
Il détermine la position d'un élément au sein de la zone d'affichage, dans les limites de son parent, en fonction de ses voisins.
Par défaut, les éléments du DOM ayant un même parent s'affichent collés les uns au-dessous des autres (sauf s'ils sont inline, nous reviendrons plus tard sur ce sujet).
Il est cependant possible de sortir un élément du flux, afin de contrôler la position où il est affiché.
Pour cela, on utilise la propriété CSS position (cumulée à des indicateurs de position tels top, left, right et bottom qui permettent de définir le décalage de l'élément par rapport à la propriété. top: 30px veut dire que l'élément se situera 30px sous le haut du parent considéré. bottom: 30px veut dire que l'élément sera situé 30px au-dessus du bas du parent considéré).
C'est la valeur par défaut affectée à chaque élément du flux HTML. L'élément est affiché selon l'ordre du flux et de conteneur.
Globalement mettre position; static sur un élément ne changera rien s'il n'avait pas de propriété position définie auparavant.
L'élément s'affiche par rapport à son parent direct. Il est toujours intégré au flux et à son conteneur, mais il est possible de choisir sa position relativement à son parent.
Les éléments alentours continuent à s'afficher comme si l'élément positionné avait sa position initiale.
Dans l'exemple https://codepen.io/c3dr0x/pen/jOwJVGj, les éléments 3 et 3-2 sont affichés relativement à leurs parents respectifs, à 30 pixels du haut et de la gauche du parent.
L'élément est retiré du flux.
Cela veut dire que ses frères s'afficheront comme s'il n'existait pas.
L'élément est positionné de façon absolue par rapport :
à son parent le plus proche dont la propriété position vaut relative ou absolute
si aucun parent n'est en position relative ou absolute, par rapport au navigateur
Si aucune propriété de positionnement (top, left, right, bottom) n'est fournie, l'élément sera placé à la position qu'il était supposé occuper dans le flux.
Dans l'exemple https://codepen.io/c3dr0x/pen/dyRrOJV :
l'élément 3-2 est positionné de façon absolue sans règle de positionnement : ainsi, il est situé à l'endroit où il aurait dû se trouver s'il était toujours dans le flux. On peut voir que 3-3 occupe toutefois cet espace sous lui. En temps normal, un div occupe 100% de la largeur de son conteneur. 3-2 étant sorti du flux, et n'ayant pas de parent, il a la largeur minimale qu'il peut avoir.
l'élément 5 es positionné de façon absolue, en top:0px et left:50%. Comme il n'a aucun parent positionné en relative ou absolute, il est positionné par rapport à la page (le conteneur de codepen est positionné et agit comme une fenêtre de navigateur).
L'élément est retiré du flux.
Il se positionne toujours par rapport à la partie visible du navigateur.
Si aucune propriété de positionnement (top, left, right, bottom) n'est fournie, l'élément sera placé à la position qu'il était supposé occuper dans le flux.
Dans l'exemple https://codepen.io/c3dr0x/pen/NWgJbym, l'élément 2 est affiché en position: fixed, en top:0px et left:50%. Si vous scrollez, vous remarquerez qu'il conserve la même position.
L'élément appartient toujours au flux. Cependant, à partir du moment où l'élément atteint une des propriétés de positionnement définies (top, left, right ou bottom), il y reste accroché.
Dans l'exemple https://codepen.io/c3dr0x/pen/RwgdoMy, l'élément 2 est défini en position: sticky, avec top: 50px. L'élément est positionné à sa position normale, cependant dès qu'on scrolle, si l'élément 2 arrive à 50 pixels du haut de l'écran, il cessera de bouger pour rester accroché à cette position.
La propriété float permet d'indiquer à un élément qu'il doit s'empiler vers un des côtés de la page (float: left, ou float: right).
Les éléments en float d'un même côté s'empilent les uns à côté des autres. S'il n'y a pas la place de s'empiler, l'élément se positionnera le plus haut possible tout en se collant sur le côté souhaité. Ce comportement est visible ici : https://float-layout.glitch.me/ ou dans cette vidéo (d'un niveau avancé, en anglais) : https://youtu.be/Y5Xa4H2wtVA?t=1540
Un élément ayant la propriété float ne prend pas de place dans son parent : en temps normal, un conteneur parent a pour taille une taille nécessaire pour contenir tous ses enfants. cependant, les éléments en float sont ignorés par leurs parents ( :'( ).
Il est cependant considéré par ses frères qui possèdent également la propriété float : les éléments s'empilent les uns à côté des autres. Ses autres frères ne possédant pas la propriété clear se positionnent derrière les éléments flottants.
Attention : les éléments en float-right sont inversés à l'affichage par rapport au DOM : le premier élément du DOM en float : right se positionne le plus à droite, le second élément sera donc positionné à sa gauche.
La propriété clear permet d'indiquer à un élément qu'il doit être attentif à ses frères en float avant de se positionner.
Un élément en clear: left se positionnera sous ses frères en float: left, mais ignorera les frère en float: right.
Pour se positionner selon tous les éléments flottants, on utilise clear: both;.
Exemple : https://codepen.io/c3dr0x/full/xxrBRQr
La propriété display définit le type de boîtes utilisé pour le rendu d'un élément.
Elle peut avoir un impact sur la relation de la boîte avec des frères, ou sur l'affichage de ses parents.
Certaines des valeurs feront l'objet d'une présentation plus poussée.
L'affichage par défaut. Un élément block s'affichera sous son précédent frère non-flottant ou positionné.
La majorité des éléments HTML est en display: block par défaut dans les feuilles de style des navigateurs.
Un élément inline s'affichera à la suite (de façon linéaire) de son précédent frère. Les objets inline n'ont ni width, ni height, et se contentent de prendre la taille de leur contenu.
Les span sont par défaut en display: inline dans les navigateurs, ce qui explique qu'il ne faut pas mettre un div (display: block) dans un span (display: inline) sous peine de devoir surcharger les valeurs de display des balises concernées.
Un jour, quelqu'un s'est demandé : mais si je veux mes boites les unes à côté des autres en contrôlant leur taille, comment je fais ? Et c'est ainsi qu'est né inline-block, qui affiche les éléments les uns à côté des autres, tout en gardant les propriétés de dimensionnement des display: block.
Exemples : https://codepen.io/c3dr0x/pen/qBjvqvV
Il s'agit de l'affichage par défaut des balises table, tr, th, td, etc.
Permet de reproduire le fonctionnement d'un tableau.
Cependant, avant de reproduire le fonctionnement d'un tableau avec des div utilisant ces propriétés, demandez-vous vraiment s'il ne vaut pas mieux utiliser table (qui est un peu fait pour ça).
Bref, à éviter.
L'élément n'est pas affiché : il est dans le DOM mais absent de la page et sa place dans le flux n'est pas réservée (contrairement aux éléments en visibility: hidden)
Flex, c'est bien.
Flex permet de gérer des affichages linéaires d'objet. Par linéaire, on entend des lignes, ou des colonnes, mais pas un tableau (il est possible de faire un tableau avec chaque ligne en affichage flex, mais les alignements peuvent ne pas être respectés).
Il permet de gérer plus facilement le positionnement, l'orientation, l'ordre d'affichage et les alignements, remplaçant ainsi la combinaison des propriétés position, display et float.
Si vous désirez en savoir plus (car il existe d'autres propriétés), vous pourrez les trouver détaillées ici : https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Pour structurer une page, des lignes, des composants, des onglets, des menus, ou plus simplement, si vous galérez à aligner un élément verticalement dans son conteneur. Oui, Flex sert aussi à ça.
Flex est compatible avec tous les navigateurs, même IE 11! http://caniuse.com/#feat=flexbox
Grid permet de positionner plus facilement les élements par rapport à leur conteneur.
Grid offre quant à lui tous les outils pour faciliter la construction des layout de page, et simplifier la mise en place de comportement responsive.
Si Flex est parfait pour gérer des lignes (ou des colonnes), Grid est l'outil permettant de travailler sur les deux dimensions en gérant les alignements de contenu comme on le souhaite.
Si vous désirez en savoir plus (car il existe d'autres propriétés), vous pourrez les trouver détaillées ici : https://css-tricks.com/snippets/css/complete-guide-grid/
Pour des layouts de page, pour des listes, des tableaux.
Attention : Grid n'est pas compatible avec IE 11 qui utilise une version antérieure de la spécification (ce qui nécessite de redéfinir toutes les propriétés juste pour IE : épargnez-vous ça)
Pour aller plus loin : une page faite intégralement sans JS basée sur Grid : http://www.hi.agency/deck/#p1
Unit | Description |
---|---|
% | pourcentage du parent |
in | pouces |
cm | centimètres (utile pour les impressions) |
mm | millimètres |
em | 1em correspond à la taille de police actuelle. 2em signifie 2 fois la taille de la police actuelle. Si un élément a une taille de police de 12px, 2em vaudra 24px. l'utilité est d'adaper le contenu à la taille de police utilisée par le lecteur, mais cela signifie aussi qu'il s'agit d'une unité inconsistante dont la valeur dépendra de la taille de police de l'endroit de la page où on l'utilise. |
rem | pareil qu'em, mais en prenant la taille de police de la racine. grâce à cela, l'unité est cohérente. |
Unit | Description |
---|---|
ex | un ex correspond à la taille-x de la police utilisée. Ici, on entre dans les métriques avancées liées aux polices, il vaut mieux éviter cette unité si on ne comprend pas comment une police marche. |
pt | point (1 pt vaut 1/72 de pouce) |
pc | pica (1 pc vaut 12 points) |
px | pixel |
vw | % de la largeur de l'écran |
vh | % de la hauteur de l'écran |
Il est possible de charger des polices supplémentaires à celles disponibles sur le navigateur.
Permet de définir le fichier de police à utiliser, le nom de la police que l'on appellera ainsi que le poids et le style pour lequel le fichier chargé s'applique.
Il est possible d'avoir plusieurs fois @font-face appelé avec la même font-family pour définir les différents états de la police.
A l'utilisation, on utilise la propriété font-family avec le nom fourni dans @font-face :
Quand un texte dépasse de sa cellule, il est maintenant possible de le tronquer automatiquement et de faire en sorte qu'il se finisse par des points de suspension (cela ne marche pas si le texte peut aller à la ligne).
Il est possible de changer l'opacité d'un élément. La propriété opacity permet de changer l'opacité de l'élément choisi au complet, mais il est possible également de choisir des couleurs transparentes à l'aide de rgba (rouge, vert, bleu, et alpha).
A noter qu'on peut s'en servir pour faire des boutons ronds si le border radius est suffisamment élevé.
S'il ne faut retenir qu'un changement, c'est calc qui prévaudra.
La fonction calc permet de calculer les mesures que l'on souhaite pour avoir un affichage parfait.
Par exemple, si on a width qui vaut 90% et margin qui vaut 100px, passé une certaine taille d'écran, l'élément et ses marges dépassent 100% de la taille disponible.
Si on souhaite avoir des marges de 100% et que l'élément occupe la taille restante, il suffit de faire :
Il est possible d'effectuer autant d'opérations que souhaité. Les opérateurs +, -, * existent, de même que / (mais de toute évidence, on ne peut diviser que par un nombre, pas par une longueur qui donnerait un résultat sans unité).
Les opérateurs + et - doivent être entourés d'espaces ! Par extension, entourez toujours les opérateurs par des espaces.
Associez les éléments de la colonne de gauche à celle droite.
Associez les éléments de la colonne de gauche à celle droite.
CSS BIO : https://css-tricks.com/combining-the-powers-of-sem-and-bio-for-improving-css/
Voici quelques liens pour les gens intéressés par les sujets abordés :
Une des meilleures formations en ligne : http://iamvdo.me/blog/ce-que-vous-avez-toujours-voulu-savoir-sur-css
Comment on faisait avant CSS (et pourquoi CSS, c'est pas si mal) : https://developer.telerik.com/topics/web-development/love-letter-css/
CSS et JS (et les petits qu'ils ont fait ensemble) : https://medium.com/seek-blog/a-unified-styling-language-d0c208de2660
Grid, c'est bien, c'est Slack qui le dit : https://slack.engineering/rebuilding-slack-com-b124c405c193
Les polices, c'est plus compliqué qu'il n'y parait (où vous apprendrez précisément ce qu'est le x-height et qu'aligner des polices différentes en maintenant une taille unique de ligne, c'est pas marrant) : https://iamvdo.me/blog/css-avance-metriques-des-fontes-line-height-et-vertical-align
Quand on utilise les media queries, il y a des effets de saut lorsqu'on passe une délimitation (genre <600px, on a un premier style, > 600px, un autre, lors du redimensionnement il y aura un saut du premier style au second). Quelqu'un a décidé de voir comment faire disparaitre ce saut pour les tailles de police. https://www.smashingmagazine.com/2017/05/fluid-responsive-typography-css-poly-fluid-sizing/
Les contextes d'empilement (avouez-le, ça vous fait rêver) : https://iamvdo.me/blog/comprendre-z-index-et-les-contextes-dempilement
Des petits détails pas inintéressants : https://medium.com/@devdevcharlie/things-nobody-ever-taught-me-about-css-5d16be8d5d0e
Une petite présentation de Houdini : https://slides.iamvdo.me/waq19/fr/#/
Un générateur de gradients linéaires : http://ourownthing.co.uk/gradpad.html (cliquez sur "Get CSS for this Gradient" pour récupérer le code)
Un site qui calcule toutes les spécificités de vos sélecteurs et en affiche un joli graphe : https://isellsoap.github.io/specificity-visualizer/ (indice: si vous avez du rouge ou des sélecteurs à complexité très haute, ce n'est pas bien)
Une spec (non encore implémentée, ne paniquez pas) pour redéfinir les propriétés en "-left" ou "-right" pour les adapter au sens de lecture (qui peut changer selon la langue, ce qui peut casser le layout de votre site). Cela consiste à utiliser des propriétés "-start" ou "-end" à la place, ce qui n'est, il faut le dire, pas con. https://drafts.csswg.org/css-logical/