Connaissez-vous bien CSS? (+ mini-test)

image

La différence entre une utilisation réussie de CSS et des tentatives douloureuses pour y faire face dépend souvent de petits détails. En fait, CSS a beaucoup de nuances. L'un des domaines les plus courants où je remarque souvent une telle lutte est la mise en page du style. Personnellement, j'aime apprendre les modèles CSS. J'ai remarqué que j'avais tendance à en utiliser un petit nombre pour résoudre la plupart des problèmes de mise en page. Cet article concerne les modèles CSS que j'utilise pour surmonter les problèmes de mise en page. Les situations seront prises en compte quelle que soit la méthodologie CSS utilisée: que ce soit SMACSS, BEM ou même un sujet CSS-in-JS brûlant, car ils se concentrent tous sur les propriétés CSS elles-mêmes, et non sur l'architecture, l'organisation ou la stratégie.



Pour le plaisir, commençons par le test.


Nous utiliserons la plate-forme que j'ai développée, appelée Questionable.io, et je l'ai utilisée pour créer un test, que nous passerons ci-dessous. Ne vous inquiétez pas, aucune donnée personnelle n'est collectée, les résultats sont anonymes et c'est absolument gratuit.

Le but du test est de voir si vous pouvez reconnaître un comportement CSS spécifique et certains problèmes sans d'abord lire l'article. Je n'allais pas rendre les tests difficiles, mais les nuances du style CSS peuvent être assez compliquées. N'oubliez pas, ce test est juste pour le plaisir. Les résultats des tests ne démontrent pas votre sang-froid, mais j'espère qu'ils seront toujours utiles.

Le test se compose de 10 questions et ne devrait pas prendre plus de 10 minutes
Du traducteur:

A la fin de l'article sur Habr, un sondage sur le nombre de points marqués au test est ajouté.

Passer le test


Remarque: si vous ne voulez pas perdre de temps, voici un lien vers des questions avec les bonnes réponses.

Avez-vous réussi le test? Super! Passons en revue les questions une par une pour avoir une meilleure idée des modèles de style qui sont affectés dans le test.

Question 1: Modèle de bloc


L'étude du modèle de bloc devrait être une priorité sur la liste de tout développeur FrontEnd. Peut-être que l'article « Le modèle CSS Box » est un peu ancien, ne sous-estimez pas sa valeur et sa pertinence pour les CSS modernes. Le modèle de bloc est à la base de presque tous les problèmes liés aux dispositions CSS.

Cette question particulière vérifie comment trouver la largeur sur la base des principes du modèle de bloc. Un bloc a une largeur explicite à travers la width: 100px , mais il s'avère que les règles de modèle de bloc par défaut appliquent les propriétés de width à la couche «contenu» de ce bloc. La largeur résultante (la largeur du bloc est dessiné sur la page) est la somme des couches de contenu, de remplissage et de bordure. Pour cette raison, la réponse est 112px.

 .box { width: 100px; /* Take this */ height: 50px; padding: 5px; /* Plus this x2 for left and right */ border: 1px solid red; /* Plus this x2 for left and right */ background-color: red; /* = 112px of computed width */ } 

Si vous êtes confronté à une situation dans laquelle la dernière colonne ou tabulation de l'interface est déplacée vers le bas à la ligne suivante, bien que vous ayez spécifié pour toute la width: 20%; et étaient sûrs qu'ils s'intégreraient à 100% de l'élément parent, cela devenait probablement un problème. Cinq colonnes d'une largeur de 20% sont placées à 100%, mais si elles reçoivent en plus un remplissage et / ou une bordure, cela augmentera la largeur de chacune, ne laissant pas assez d'espace dans la ligne actuelle pour la dernière colonne.

Lorsque CSS3 a été introduit, un nouvel outil appelé box-sizing . Cela nous permet de contrôler à quelle couche du modèle de bloc nous voulons appliquer la propriété width . Par exemple, nous pouvons spécifier le box-sizing: border-box . Cela signifie que nous voulons que toutes les règles de largeur soient appliquées à la couche de bordure extérieure au lieu de la couche de contenu. Dans la question du test, si la propriété box-sizing: border-box était appliquée, la largeur de bloc résultante était de 100 pixels.

Pour certains d'entre vous, c'est un fait bien connu, mais ce sera quand même un bon rappel pour les professionnels comme pour les débutants.

Il existe un certain nombre d'articles sur le modèle de bloc et sur la façon d'utiliser la propriété de dimensionnement de boîte comme réinitialisation pour l'appliquer immédiatement à l'ensemble du projet. Box Sizing et Inheriting box-sizing Probablement légèrement meilleures Les meilleures pratiques sont deux bons articles CSS-Tricks à lire.

Question 2: Limites des éléments


La deuxième question test peut être considérée en partie comme la continuation de la première. Rappelez-vous, c'est une chose à lire: "Le modèle de bloc a des couches (contenu, remplissage, bordure) et toutes affectent la largeur et la hauteur totales de l'élément", une autre chose est de pouvoir reconnaître les problèmes du modèle de bloc dans une situation réelle. Ce problème particulier est un peu un classique parmi ceux qui travaillent avec CSS depuis un certain temps. Il résulte du fait que les cadres occuperont un certain espace supplémentaire et repousseront les éléments environnants, car ils font partie du modèle de bloc. L'ajout de cadres tout en changeant l'état d'un élément, tel que :hover , signifie que les blocs deviendront plus grands, puis les blocs qui suivent seront poussés vers le bas. Cela peut être gênant :


De toutes les solutions possibles mentionnées dans la question de test, l'ajout de border: 2px solid transparent à l'état d'origine (sans survol) est la seule solution possible au problème. box-sizing ne résout pas ce problème, car nous ne définissons pas explicitement la hauteur. Si nous faisions cela, le cadre ferait partie de la hauteur globale de l'élément et le décalage ne se produirait pas, mais ce n'est pas notre cas.

Il existe d'autres solutions que nous n'avons pas mentionnées dans les options de réponse. L'un d'eux ajoute une pseudo-bordure en utilisant la propriété box-shadow ou en utilisant le outline au lieu de la border . Chacun d'eux ne conduira pas à un biais, car il ne s'agit pas d'une couche du modèle de bloc. Voici un autre article CSS-Tricks où vous pouvez en savoir plus sur ces solutions.

Remarque:
N'oubliez pas que le outline ne prend pas en charge border-radius

Question 3: Positionnement - absolu vs fixe


En plus de comprendre quand utiliser chacun des types et comment ils diffèrent dans la représentation visuelle , il est également très important de connaître les règles de la façon dont chacune des méthodes de positionnement est liée à l'élément parent en utilisant les propriétés haut, droite, bas ou gauche.

Tout d'abord, regardons le bloc conteneur . Une brève définition est que le bloc conteneur est le plus souvent le parent de tout élément en question. Cependant, les règles pour le bloc conteneur sont différentes pour les éléments positionnés de manière absolue et fixe.

1) Pour les éléments absolus . Le bloc conteneur est l'ancêtre le plus proche dont le positionnement n'est pas static . Par exemple, lorsqu'un élément est positionné de manière absolue et contient les propriétés top , right , bottom ou left , il sera positionné par rapport à tout parent ayant un positionnement absolute , relative , fixed ou sticky .
2) Pour les éléments fixes . Le bloc conteneur est la fenêtre, malgré la présence d'éléments parents dont le positionnement n'est pas static . De plus, le comportement de défilement est différent des éléments positionnés de manière absolue. Les éléments fixes restent «fixes» dans la zone d'affichage, d'où le nom.

De nombreux développeurs pensent que les éléments positionnés de manière absolue ne recherchent que l'élément parent le plus proche avec une position de position: relative . Cette idée fausse s'est répandue simplement parce que position: relative plus souvent spécifiée associée à position: absolute pour créer un bloc conteneur. La raison pour laquelle cela est souvent utilisé est que le positionnement relatif du bloc parent le laisse dans le flux , ce qui est souvent préféré. Il y a des situations où le parent d'un élément absolument positionné est lui-même absolument positionné. C'est tout à fait normal. Si tous les parents sont statiques, un élément positionné de façon absolue sera attaché à la fenêtre - mais de façon à ce qu'il défile avec la fenêtre.


Il y a un ajout peu connu aux règles mentionnées ci-dessus: dans les situations où l'élément parent a ( entre autres ) la propriété transform avec une valeur autre que none , il devient un bloc conteneur pour les éléments positionnés de manière absolue et fixe. La confirmation de cela peut être vue dans CodePen, où l'élément avec le texte "Remarque!" Est un élément fixe, et le parent a la propriété transform, mais uniquement lorsque le curseur de la souris est au-dessus (dans l'état :hover )


Question 4: réduire la marge des éléments parent et enfant


C'est l'une de ces petites choses CSS qui peuvent causer beaucoup de problèmes si vous ne savez pas comment cela fonctionne. Il existe un concept appelé marges d'effondrement et de nombreuses personnes en connaissent la manifestation, appelées marges d'effondrement des frères et sœurs adjacents. Cependant, il existe une autre forme, appelée les marges de réduction du parent et du premier / dernier enfant, qui est moins connue. Voici une démonstration des deux cas:


Chaque balise de paragraphe a une marge supérieure et inférieure égale à 1em, qui est stylisée par le navigateur. Jusqu'à présent, c'est la partie la plus facile de la situation. Mais pourquoi l'espacement entre les paragraphes n'est-il pas 2em (la somme du haut et du bas)? C'est ce qu'on appelle l'effondrement des marges des frères et sœurs adjacents. Les marges se chevauchent de telle sorte que la plus grande des deux marges sera la taille de l'écart, donc dans ce cas, l'écart sera de 1em.

Cependant, quelque chose d'autre étrange se produit. Avez-vous remarqué que la marge supérieure du premier paragraphe ne crée pas d'écart entre celui-ci et la div du conteneur bleu? Au lieu de casser, il semble intégrer une marge dans le div parent, comme si le div avait une marge supérieure. Cela s'appelle Réduire les marges du parent et du premier / dernier enfant. Ce type de marges d'effondrement ne se produira pas dans certaines circonstances si les caractéristiques suivantes sont caractéristiques du parent:

  • Il y a un rembourrage supérieur / inférieur supérieur à zéro
  • Il y a une bordure supérieure / inférieure supérieure à zéro
  • Un contexte de formatage de bloc est spécifié qui peut être créé à l'aide de overflow: hidden ou overflow: auto
  • Affichage: ensemble de propriétés flow-root (mauvaise prise en charge du navigateur)

Lorsque je suis heureux d'expliquer aux gens ce petit détail CSS et de le résoudre avec un remplissage ou une bordure, la réponse est presque toujours: «Qu'en est-il du remplissage ou de la bordure égal à 0?». Eh bien, cela ne fonctionne pas, car la valeur doit être un entier positif.

Dans l'exemple précédent, le remplissage 1px nous permet de basculer entre l'utilisation de la réduction et la prévention de la réduction des marges du parent et de l'enfant. L'écart qui apparaît entre le premier / dernier paragraphe et le parent est le remplissage 1px, mais maintenant la marge est considérée à l'intérieur du conteneur, car la couche de remplissage crée une barrière pour empêcher les marges de s'effondrer.

Quant à la question, je suis sûr que vous pouvez voir quel est le problème dans cette interface:


Le premier élément avec la classe .comment (sans la classe .moderator ) réduit les marges. Même sans regarder le code, nous pouvons voir que l'élément avec la classe .moderator a une trame, et l'élément sans cette classe n'en a pas. Il y avait en fait trois réponses à cette question qui étaient considérées comme correctes. Chacune d'entre elles, en fait, est déjà appliquée dans la source CodePen, elles sont juste commentées.

L'une des raisons pour lesquelles ce type de marges d'effondrement n'est pas aussi largement connue que les autres est qu'il existe de nombreuses situations dans lesquelles nous pouvons accidentellement l'éviter. Les éléments Flexbox et Grid créent un contexte de formatage de bloc, donc lorsque vous les utilisez, nous ne rencontrons pas ce type de marges de réduction. Si l'interface de nos commentaires était un vrai projet, il y a de fortes chances que des rembourrages soient placés sur les quatre côtés pour laisser de l'espace autour, ce qui, à son tour, a corrigé l'effondrement des marges pour nous.

Question 5: Pourcentage de quoi?


Lorsque des unités de pourcentage sont utilisées, les pourcentages sont basés sur la largeur ou la hauteur du bloc conteneur (généralement le parent). Comme nous l'avons dit précédemment, un élément avec la propriété transform deviendra un bloc conteneur, donc lorsque l'élément utilise la transformation, les unités en pourcentage (uniquement pour la transform ) sont sur la propre taille de l'élément, et non sur la taille parent.

Dans l'exemple ci-dessous, nous pouvons voir que 50% prennent deux valeurs différentes selon le contexte. Le premier bloc rouge a la propriété margin-left: 50% , et le deuxième bloc rouge utilise transform: translateX(50%) .


Question 6: Le modèle de bloc frappe à nouveau ...


Seulement, vous pensiez que nous avions fini de parler du modèle de bloc ...


Le problème est dû au fait que nous utilisons la width: 100% pour le pied de page et en même temps ajoutons un rembourrage. La largeur du conteneur est de 500 pixels, ce qui signifie que la couche de contenu de pied de page (100%) est également de 500 pixels avant que les rembourrages ne soient ajoutés à cette taille.

Le problème peut être résolu par l'une des deux techniques courantes:

  1. Utilisez la propriété box-sizing pour le pied de page directement ou via la réinitialisation mentionnée précédemment
  2. Supprimez la propriété width de l'élément et utilisez à la place les propriétés left: 0 et right: 0 . Il s'agit d'un bon exemple d'utilisation simultanée des propriétés left et right . Cette approche évite les problèmes du modèle de bloc, car la propriété width utilisera sa valeur par défaut auto pour remplir tout espace disponible entre le remplissage et les bordures lorsque left: 0 et right:0 .

Remarque: Une option était de supprimer le rembourrage du pied de page. Techniquement, cela résoudrait le problème, car la couche de contenu serait à 100% et n'aurait pas de rembourrage ou de bordure pour s'étendre au-delà de la largeur du conteneur. Mais je pense que cette solution est la mauvaise approche, car nous n'avons pas à changer notre interface pour nous adapter aux problèmes du modèle de bloc, qui sont facilement corrigés sans lui.

La réalité pour moi est que j'ai toujours la propriété box-sizing: border-box dans le cadre de ma réinitialisation générale du style. Si vous faites de même, vous rencontrez très probablement rarement ce problème. Mais j'aime toujours la technique avec la définition des propriétés left:0 et right:0 en même temps, car, comme le montre l'heure, c'est plus fiable (en tout cas, à en juger par mon expérience) que de résoudre les problèmes du modèle de bloc qui se posent en raison de la largeur 100%

Question 7: Centrage des éléments absolus et fixes


Maintenant, nous commençons vraiment à combiner tout le matériel décrit ci-dessus, avec le centrage des éléments absolus et fixes:


Étant donné que nous avons déjà couvert la plupart des éléments de cette question de test, j'indique simplement que le centrage horizontal et vertical peut être effectué en utilisant la méthode de la vieille école via des marges négatives, ou plus récent en utilisant la propriété transform. J'attire également votre attention sur un excellent guide de centrage des éléments CSS-Tricks .

Remarque : il y a quelque temps, on a fait valoir que si nous connaissons la largeur et la hauteur du bloc, nous devrions utiliser des marges négatives, car elles fonctionnent de manière plus stable que la nouvelle propriété de transformation. Pour le moment, la transformation fonctionne de manière stable et j'utilise presque toujours cette propriété, sauf si j'ai besoin d'éviter de convertir le bloc en bloc contenant.

Question 8: Centrage des éléments dans un flux normal


Flexbox nous a apporté de nombreux outils incroyables pour résoudre des problèmes de mise en page complexes. Avant sa sortie, il a été signalé que le centrage vertical était l'une des fonctionnalités les plus complexes implémentées dans CSS. Avec l'avènement de Flexbox, le centrage vertical est devenu une routine:

 .parent { display: flex; } .child { margin: auto; } 

https://codepen.io/bradwestfall/pen/GPNmbM
Remarque : notez que pour les éléments flexibles, margin: auto est appliqué en haut, en bas, à droite et à gauche pour centrer l'élément verticalement et horizontalement. Auparavant, le centrage vertical ne fonctionnait pas pour les éléments de bloc, donc la margin: 0 auto; assez courante margin: 0 auto;

Question 9: Calculs avec différentes unités


L'utilisation de la fonction calc () est idéale lorsque vous devez travailler avec deux unités de mesure que nous ne pouvons pas additionner par nous-mêmes ou lorsque nous devons rendre les fractions plus faciles à comprendre . Cette question test nous propose de découvrir à quoi ressemblera le résultat de l'expression calc(100% + 1em) , à partir du fait que la largeur de l'élément div est de 100px. Cela pourrait être un peu déroutant, car en fait, peu importe que la largeur de l'élément div soit de 100 pixels. Les pourcentages commencent toujours par la largeur du parent, donc la bonne réponse était: «100% du bloc contenant (parent) plus 1em».

Il y a plusieurs situations dans lesquelles j'utilise régulièrement calc() . Premièrement, chaque fois que je veux déplacer quelque chose de 100%, mais aussi ajouter une quantité fixe d'espace supplémentaire. Les menus déroulants peuvent en être un bon exemple:


La particularité ici est que nous voulons créer un menu déroulant qui peut être utilisé avec les éléments d'appel de différentes tailles (dans ce cas, deux tailles de boutons différentes). Nous ne savons pas quelle sera la hauteur de l'élément appelant ce menu, mais nous savons que le top: 100% placera le bord supérieur du menu déroulant au bord inférieur du bouton d'appel. Si chaque menu doit être au bord inférieur du bouton correspondant, plus 0,5em, cela peut être réalisé avec calc(100% + 0.5em) . Bien sûr, nous pourrions également utiliser top: 110% , mais ces 10% supplémentaires dépendraient de la hauteur du bouton d'appel et du conteneur.

Question 10: Marges négatives


Contrairement aux marges positives qui repoussent les frères et sœurs, les marges négatives les rapprochent les uns des autres sans déplacer les frères et sœurs . Cette dernière question de test propose deux solutions, toutes deux éliminant techniquement la double bordure dans notre groupe de boutons, mais je préfère fortement la technique de la marge négative, car la suppression des cadres rendrait plus difficile l'exécution de certaines techniques, telles que l'effet de survol.


L'effet résultant est une «bordure commune» qui s'affiche entre les boutons. En fait, les boutons ne peuvent pas avoir de bordure commune, nous devons donc utiliser une technique de marge négative pour qu'une image en chevauche une autre. Ensuite, j'utilise z-index pour définir le cadre que je souhaite placer au-dessus d'un autre, en fonction de l'état du survol de la souris. Notez que le z-index est utile ici même sans utiliser le positionnement absolu, mais vous avez dû définir la position: relative . Si j'utilisais la technique de suppression du cadre gauche du deuxième bouton, cet effet serait beaucoup plus difficile à mettre en œuvre.

Tout cela a du sens.


Je veux vous montrer une autre dernière démo qui utilise beaucoup des astuces dont nous avons discuté auparavant. La tâche consiste à créer des tuiles qui s'étendent sur les bords gauche et droit du conteneur, en tenant compte de l'indentation. Par tuiles, je veux dire la possibilité d'avoir une liste de blocs qui passent à la ligne suivante lorsqu'il n'y a pas assez d'espace en largeur. Passez la souris sur les tuiles pour voir le résultat:


Un obstacle dans l'exécution de cette tâche est l'indentation. Sans rembourrage, il serait facile d'obtenir des tuiles adjacentes aux bords gauche et droit du conteneur. Le problème est que les retraits seront créés à l'aide de marges, et lorsque nous ajoutons des marges de tous les côtés de la mosaïque, nous créons deux problèmes:

  1. La présence de trois tuiles d'une largeur de 33.33% en conjonction avec la marge ne pourra pas tenir dans une rangée. Bien que le box-sizing nous permette d'avoir un rembourrage et des bordures sur l'élément .tile et de tenir dans 33.33% , cela ne nous aidera pas dans le cas des marges - ce qui signifie que la largeur calculée des trois tuiles sera supérieure à 100%, ce qui forcera la dernière tuile à passer à la suivante chaîne.
  2. Les tuiles gauche et droite ne reposeront plus contre le bord du conteneur.

Le premier problème peut être résolu avec calc((100% / 3) - 1em). Ce qui signifie 33,33% moins les marges gauche et droite de chaque tuile. L'effondrement des éléments frères adjacents ne se produira pas ici, car il n'est possible que sur les marges supérieure et inférieure. Par conséquent, la distance horizontale entre deux tuiles est la somme de deux marges (1em). Dans ce cas, l'effondrement ne s'applique pas non plus aux marges supérieure et inférieure, car les première et dernière tuiles ne sont pas techniquement adjacentes, même si visuellement l'une est sous l'autre.

En prenant aveccalc()Trois tuiles peuvent tenir dans une rangée, mais elles ne touchent toujours pas les bords du conteneur. Pour ce faire, nous pouvons utiliser des marges négatives de taille égale aux marges gauche et droite de chaque tuile. La ligne pointillée verte dans l'exemple est un conteneur dans lequel nous appliquons des marges négatives pour dessiner des tuiles correspondant au bord du contenu environnant. Nous pouvons voir comment ils s'adaptent à la zone de remplissage de l'élément parent. Ceci est normal car les marges négatives ne repoussent pas les éléments voisins environnants.

Par conséquent, nous obtenons des tuiles qui ont suffisamment d'espaces qui s'étendent d'un bord à l'autre pour s'aligner avec les balises de paragraphe adjacentes à l'extérieur des tuiles.

Il existe de nombreuses façons de fabriquer des carreaux (et ils ont généralement leurs avantages et leurs inconvénients). Par exemple, il existe une solution de grille CSS assez élégante dont Haydon Pickering a parlé. Cette solution est implémentée à l'aide d'une technique qui simule les demandes de conteneurs (mais en utilisant la magie de grille). En fin de compte, sa solution utilisant Grid est meilleure que flexbox, ce que j'ai démontré mais a un support de navigateur pire.

Résumé


Au début, j'ai déclaré que j'étais enclin à rechercher des modèles pour résoudre les problèmes. Cet article ne traite pas tant des scénarios présentés ci-dessus; il s'agit davantage d'un ensemble d'outils qui peuvent être utilisés pour résoudre ces problèmes et bien d'autres problèmes de composition auxquels nous pouvons tous faire face. J'espère que ces outils vous aideront.

Soit dit en passant, il existe un certain nombre d'excellentes ressources qui examinent attentivement le sujet du modèle de bloc. Tout d'abord, des articles de Rachel Andrew et Jen Simmons, qui valent vraiment la peine d'être lus.

  • Box Alignment Cheatsheet est un excellent matériau avec des éléments visuels qui mettent l'accent sur diverses propriétés qui affectent la façon dont les éléments s'alignent seuls ou par rapport à d'autres éléments.
  • Jen Simmons Labs — , .

Source: https://habr.com/ru/post/fr467555/


All Articles