Méthodes et outils pour développer des styles de page Web

Ne tournons pas autour du pot, avouons-le: le processus d'Ă©criture d'un bon code CSS peut ĂȘtre trĂšs, trĂšs difficile. De nombreux dĂ©veloppeurs ne veulent pas jouer avec les styles. Ils sont prĂȘts Ă  tout, mais pas CSS.



L'auteur du document, dont nous portons aujourd'hui la traduction Ă  votre attention, dit qu'il n'a pas aimĂ© lui-mĂȘme la partie du dĂ©veloppement Web liĂ©e au CSS. Mais il n'y a pas moyen de le contourner. De nos jours, une grande attention est accordĂ©e Ă  la conception et Ă  ce que l'on appelle "l'expĂ©rience utilisateur", mais vous ne pouvez pas vous passer de CSS. Le but de ce matĂ©riel est d'aider tout le monde Ă  amĂ©liorer ses compĂ©tences dans le dĂ©veloppement et l'application de styles de page Web.

ProblĂšmes CSS


Au tout début d'un nouveau projet, les styles semblent généralement simples et clairs. Disons qu'il y a trÚs peu de sélecteurs CSS, tels que .title , input , #app , qui ne seront pas difficiles à utiliser.

Mais, Ă  mesure que l'application se dĂ©veloppe, les styles se transforment en cauchemar. Le dĂ©veloppeur commence Ă  ĂȘtre confus au sujet des sĂ©lecteurs CSS. Il dĂ©couvre qu'il Ă©crit quelque chose comme div#app .list li.item a . Cependant, le travail ne peut pas ĂȘtre arrĂȘtĂ©, donc le programmeur continue d'utiliser des constructions similaires, le code CSS est poussĂ© quelque part Ă  la fin du fichier. Et vraiment - qui s'intĂ©resse aux styles? Et le CSS lui-mĂȘme est tellement absurde ... Le rĂ©sultat est 500 lignes de CSS complĂštement non pris en charge, terribles.

J'aimerais que vous lisiez cet article, que vous regardiez vos projets précédents et que vous pensiez: "Eh bien, wow, comment pourrais-je écrire ceci?"

Vous pensez peut-ĂȘtre maintenant que «écrire du CSS» signifie utiliser des frameworks CSS. AprĂšs tout, ils visent prĂ©cisĂ©ment Ă  faciliter le travail avec les styles, et c'est avec leur utilisation qu'ils Ă©crivent un bon code CSS. Tout cela est vrai, mais les frameworks CSS prĂ©sentent certains inconvĂ©nients:

  • Souvent, leur utilisation conduit Ă  l'apparition d'un design ennuyeux, monotone et banal.
  • Il est difficile de personnaliser les styles des cadres et la nĂ©cessitĂ© de faire quelque chose qui dĂ©passe le cadre du cadre peut entraĂźner des difficultĂ©s.
  • Le framework, avant de les utiliser, doit ĂȘtre Ă©tudiĂ©.

Et au final, vous ne lisez pas ceci pour vous familiariser avec un certain cadre? Faisons donc CSS. Je voudrais tout de suite noter que la matiÚre n'est pas sur la façon de créer de beaux designs pour des applications. Il s'agit de savoir comment écrire du CSS de qualité facile à maintenir et comment l'organiser correctement.

SCSS


Dans mes exemples, j'utiliserai SCSS . Il s'agit d'un préprocesseur CSS. En fait, SCSS est un sur-ensemble de CSS. Il a des fonctionnalités trÚs intéressantes, telles que les variables, les constructions imbriquées, l'importation de fichiers, les mixins. Nous discuterons des fonctionnalités SCSS que nous utiliserons.

▍Variables


Dans SCSS, vous pouvez utiliser des variables. Le principal avantage de l'utilisation de variables est la possibilité de leur réutilisation. Imaginez que nous ayons un ensemble de couleurs pour l'application. La couleur principale est le bleu. En conséquence, cette couleur est appliquée littéralement partout. Il est utilisé dans la propriété background-color des boutons, dans la propriété color du titre de la page et dans de nombreux autres endroits.

Et puis, tout Ă  coup, vous dĂ©cidez de passer du bleu au vert. Si vous effectuez un tel remplacement sans utiliser de variables, vous devrez Ă©diter tout le code, toutes les lignes oĂč l'ancienne couleur est utilisĂ©e. Si vous utilisez une variable, vous n'aurez qu'Ă  modifier sa valeur. Voici Ă  quoi ressemble l'utilisation des variables:

 //   $primary-color: #0099ff; //   h1 { color: $primary-color; } 

▍ Constructions imbriquĂ©es


SCSS prend en charge les constructions imbriquées. Voici le CSS régulier:

 h1 { font-size: 5rem; color: blue; } h1 span { color: green; } 

GrĂące au support des constructions imbriquĂ©es, il peut ĂȘtre transformĂ© comme suit:

 h1 { font-size: 5rem; color: blue; span {   color: green; } } 

Cette option est beaucoup plus facile à lire, non? De plus, grùce à l'utilisation de constructions imbriquées, le temps de création de sélecteurs complexes est réduit.

▍Fragmentation et importation


Lorsqu'il s'agit de prendre en charge les styles et leur lisibilitĂ©, il devient clair qu'il est impossible de conserver tout le code dans un seul fichier. Un fichier de style peut ĂȘtre utilisĂ© Ă  des fins expĂ©rimentales ou lors du dĂ©veloppement d'une petite application, mais si vous passez Ă  un niveau professionnel ... il vaut mieux ne mĂȘme pas essayer. Heureusement pour nous, SCSS a des mĂ©canismes en place pour organiser facilement le code de style.

Les fichiers contenant des fragments de descriptions de style peuvent ĂȘtre créés en ajoutant un trait de soulignement au dĂ©but de leurs noms: _animations.scss , _base.scss , _variables.scss , etc.

La directive @import est utilisée pour importer ces fichiers. Voici comment utiliser ce mécanisme:

 //  _animations.scss @keyframes appear { 0% {   opacity: 0; } 100% {   opacity: 1; } } //  header.scss @import "animations"; h1 { animation: appear 0.5s ease-out; } 

Vous pouvez constater qu'il y a une erreur dans ce code. En effet, le fichier que nous voulons importer s'appelle _animations.scss , et nous, dans le fichier header.scss , utilisons la commande @import "animations" . Cependant, il n'y a pas d'erreur. SCSS est un systÚme suffisamment intelligent pour comprendre que dans une telle situation, le développeur signifie le fichier correspondant.

C'est tout ce que nous devons savoir sur les variables, les constructions imbriquées, la fragmentation des styles et l'importation. Il existe d'autres fonctionnalités dans SCSS, telles que les mixins, l'héritage et d'autres directives (parmi elles sont @for , @if et quelques autres), mais nous n'en parlerons pas ici.

Si vous souhaitez mieux connaĂźtre SCSS, consultez la documentation correspondante.

Organisation CSS: méthodologie BEM


Je ne me souviens pas combien de fois j'ai utilisé des termes universels pour nommer les classes CSS. En conséquence, je pense que ces noms me sont familiers: .button , .page-1 , .page-2 , .custom-input .

Souvent, nous ne savons tout simplement pas comment nommer certaines entités. Mais c'est trÚs important. Et si vous développiez l'application, puis, pour une raison quelconque, reportiez le travail de plusieurs mois? Ou, et c'est bien pire, et si quelqu'un d'autre se chargeait de ce projet? Si le code CSS utilise des noms inappropriés, il sera difficile à comprendre sans analyser d'autres parties de l'application.

La mĂ©thodologie BEM (Block, Element, Modifier) ​​est une approche composante du dĂ©veloppement web. En particulier, il s'agit d'une convention de dĂ©nomination d'entitĂ©. Cette mĂ©thodologie vous permet de structurer le code, de le dĂ©composer en modules et de faciliter sa rĂ©utilisation. Parlons des blocs, des Ă©lĂ©ments et des modificateurs.

▍ Blocs


Les blocs peuvent ĂȘtre considĂ©rĂ©s comme des composants. Vous avez sĂ»rement jouĂ© enfant dans Lego. Par consĂ©quent, allumez la machine Ă  voyager dans le temps.

Comment avez-vous construit, disons, une maison ordinaire? Ici, vous aurez besoin d'une fenĂȘtre, d'un toit, d'une porte, de murs et, en gĂ©nĂ©ral, cela suffit. Ce sont tous nos blocs. Ils sont importants en eux-mĂȘmes.

Dénomination: nom du bloc - .block

Exemples: .card , .form , .post , .user-navigation

▍ ÉlĂ©ments


Comment faire une fenĂȘtre Lego? Probablement, certains cubes ressemblent Ă  des cadres, donc si vous connectez quatre de ces cubes, vous obtenez une belle fenĂȘtre. Ce sont les Ă©lĂ©ments. Ils font partie de blocs, nous en avons besoin pour crĂ©er des blocs. Cependant, les Ă©lĂ©ments en dehors des blocs sont inutiles.

+ __ + : + __ + - .block__element

Exemples: .post__author , .post__date , .post__text

▍ Modificateurs


Une fois que vous avez une fenĂȘtre, vous pouvez la modifier. Par exemple - peignez dans une couleur diffĂ©rente. Ces modifications des blocs de base ou des Ă©lĂ©ments sont effectuĂ©es Ă  l'aide de modificateurs. Ce sont des drapeaux de blocs ou d'Ă©lĂ©ments, et ils sont utilisĂ©s pour changer leur comportement, leur apparence, etc.

+ -- + : + -- + - .block__element--modifier , .block--modifier
Exemples: .post--important , .post__btn--disabled

▍ Remarques


  • Lorsque vous utilisez BEM, les noms sont donnĂ©s exclusivement aux classes. Aucun ID ou balise - juste des classes.
  • Les blocs ou Ă©lĂ©ments peuvent ĂȘtre imbriquĂ©s dans d'autres blocs ou Ă©lĂ©ments, mais ils doivent ĂȘtre complĂštement indĂ©pendants. C'est trĂšs important. Par consĂ©quent, par exemple, vous n'avez pas besoin d'affecter des champs au bouton car vous souhaitez le placer sous l'en-tĂȘte, sinon le bouton sera associĂ© Ă  l'en-tĂȘte. Utilisez plutĂŽt des classes d'assistance.
  • Lors de l'application de la mĂ©thodologie BEM, les fichiers HTML seront surchargĂ©s de noms, mais c'est une somme modique pour les fonctionnalitĂ©s que BEM nous offre.

▍Exercice


Voici un exercice. Examinez attentivement les sites que vous aimez ou ceux que vous utilisez le plus souvent, et rĂ©flĂ©chissez Ă  ce qui peut ĂȘtre un blocage sur eux, Ă  ce qui est un Ă©lĂ©ment et Ă  ce qu'est un modificateur.

Par exemple, voici ce que j'ai obtenu en analysant le Google Store.


Analyse du site

Maintenant c'est ton tour. Regardez le site, rĂ©flĂ©chissez Ă  comment il peut ĂȘtre amĂ©liorĂ©. Afin de se dĂ©velopper dans un certain domaine, une personne doit rechercher indĂ©pendamment des informations, expĂ©rimenter et crĂ©er quelque chose de nouveau.

▍ Exemples


Voici un exemple préparé par Codepen qui démontre les capacités de BEM. Ici, nous distinguons un peu quelque chose comme la publication dans un certain blog. Voici le HTML de cet exemple.

 <div class="post"> <span class="post__author">Thomas</span>     <span class="post__date">3 minutes ago</span> <p class="post__text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam sit voluptatem aut quis quisquam veniam delectus sequi maxime ullam, inventore blanditiis quia commodi maiores fuga, facere quaerat doloremque in. Nisi!</p> </div> <div class="post mt-large post--important"> <span class="post__author">Thomas</span>     <span class="post__date">2 hours ago</span> <p class="post__text">Voluptatem incidunt autem consequatur neque vitae aliquam, adipisci voluptatum. Ipsum excepturi dolores exercitationem rem ab similique consequatur nesciunt, tempora aut vel unde.</p> </div> 

Voici les styles SCSS:

 .post { display: inline-block; padding: 1rem; background-color: #ccc; border: 1px solid #222; border-radius: 5px; &--important {   background-color: yellow; } &__author {   font-size: 1.2rem;   font-weight: bold;   color: blue; } &__date {   float: right; } &__text {   line-height: 2rem;   font-size: 1.3rem; } } .mt-large { margin-top: 3rem; } 

Mais que s'est-il finalement passé?


Faire des "publications" avec BEM

Prenons un autre exemple . Ici, en utilisant BEM, nous distinguons les boutons. Voici le HTML de cet exemple.

 <div> <button class="btn">   Click me </button> <button class="btn btn--danger">   Danger </button> <button class="btn btn--success">   Success </button> <button class="btn btn--small">   Small </button> <button class="btn btn--big">   Big </button> <button class="btn btn--border">   Border </button> </div> 

Voici les styles SCSS.

 .colors { font-size: 1.5rem; font-family: sans-serif; } .btn {   background-color: #FF6B93;   color: #fff;   text-transform: uppercase;   padding: 1.5rem 2.5rem;   border-radius: 4px;   transition: all .2s;   font-size: 1.3rem;   border: none;   letter-spacing: 2px;   cursor: pointer; &:hover {   background-color: #D15879; } &:focus {   outline: none; } &--danger {   background-color: #FF3B1A;     &:hover {     background-color: #D43116;   } } &--success {   background-color: #00D123;     &:hover {     background-color: #00AB1D;   } } &--small {   padding: 1rem 2rem;   font-size: 1rem; } &--big {   padding: 1.8rem 4.5rem;   font-size: 1.7rem; } &--border {   background-color: #fff;   color: #FF6B93;   border: 1px solid #FF6B93;     &:hover {     background-color: #FF6B93;     color: #fff;   } } } 

Et voici le résultat.


Conception de boutons à l'aide de la méthodologie BEM

Organisation des fichiers CSS: le modĂšle 7-1


Parlons de l'organisation des fichiers CSS. Ce que vous apprenez de cette partie de notre conversation vous permettra de travailler de maniÚre plus productive et vous aidera, dans des situations appropriées, à trouver instantanément le code CSS à modifier. Pour y parvenir, nous devons étudier le modÚle "7-1".

Il vous semblera peut-ĂȘtre maintenant que ce modĂšle est en quelque sorte trop Ă©trange. Cependant, il n'y a rien d'Ă©trange ici, et son utilisation est trĂšs simple. Pour ce faire, il suffit d'observer deux rĂšgles simples:

  1. Tous les fichiers contenant des fragments SCSS doivent ĂȘtre placĂ©s dans 7 dossiers diffĂ©rents.
  2. Tous ces fichiers doivent ĂȘtre importĂ©s dans un fichier, main.scss , situĂ© dans le rĂ©pertoire racine dans lequel se trouvent tous ces dossiers.

Par consĂ©quent, le nom du modĂšle peut ĂȘtre dĂ©cryptĂ© en «7 dossiers - 1 fichier». Comme vous pouvez le voir, ce n'est pas si difficile. Parlons plus en dĂ©tail de ce modĂšle.

▍ 7 dossiers


Voici les dossiers en question:

  1. base : dans ce dossier, vous devez placer tout, pour ainsi dire, le code "modÚle". Par code "modÚle", nous entendons ici tout le code CSS que vous devez écrire lors de la création d'un nouveau projet. Par exemple: rÚgles typographiques, animations, utilitaires (c'est-à-dire des classes comme margin-right-large , text-center ), etc.
  2. components : le nom de ce dossier indique clairement ce qui y sera stockĂ©. Nous parlons des styles de composants utilisĂ©s pour crĂ©er des pages. Ce sont des boutons, des formulaires, toutes sortes de curseurs, des fenĂȘtres contextuelles, etc.
  3. layout : ce dossier est utilisĂ© pour stocker les styles des Ă©lĂ©ments de mise en page. Il s'agit de l'en-tĂȘte et du pied de page de la page, de la zone de navigation, des diffĂ©rentes sections de la page, de la grille, etc.
  4. pages : parfois un projet a besoin de pages qui ont leur propre style spécifique, différent du style des autres pages. Les descriptions de style de ces pages spéciales se trouvent ici dans ce dossier.
  5. themes : si un projet Web implique l'utilisation de diffĂ©rents thĂšmes (par exemple, quelque chose comme «mode sombre» ou «admin»), les styles pour eux doivent ĂȘtre mis ici.
  6. abstracts : toutes sortes de choses auxiliaires entrent dans ce dossier - fonctions, variables, mixins.
  7. vendors : un site rare sans dépendances externes. Ce dossier contient des styles qui ne sont pas créés par ceux qui développent un site particulier. Ici, par exemple, vous pouvez enregistrer les fichiers de projet Font Awesome, les styles Bootstrap, etc.

▍Fichier main.scss


C'est dans ce fichier que tous les fragments de styles disposés dans les sept dossiers ci-dessus sont importés. Une partie de ce fichier pourrait ressembler à ceci:

 @import abstracts/variables; @import abstracts/functions; @import base/reset; @import base/typography; @import base/utilities; @import components/button; @import components/form; @import components/user-navigation; @import layout/header; @import layout/footer; 

Je ne peux pas ĂȘtre d'accord avec le fait que toute cette conception de sept dossiers semble assez grande. Cependant, il convient de noter que cette architecture est conçue pour les grands projets. Pour les petits projets, vous pouvez utiliser la version adaptĂ©e du modĂšle "7-1". Les caractĂ©ristiques de cette version sont qu'elle peut se passer de certains dossiers. Donc, ici, vous pouvez refuser le dossier des vendors en plaçant des liens vers des feuilles de style externes au projet dans la balise de link . De plus, vous pouvez vous passer du dossier des themes , car, probablement, les thĂšmes ne seront pas utilisĂ©s dans une petite application Web. Et enfin, vous pouvez vous dĂ©barrasser du dossier des pages , car dans ce projet, trĂšs probablement, il n'y aura pas de pages dont le style est trĂšs diffĂ©rent du style gĂ©nĂ©ral. En consĂ©quence, sur sept dossiers, il n'en reste que quatre.

De plus, en faisant un petit projet, vous pouvez aller de deux maniĂšres:

  • Si vous prĂ©fĂ©rez utiliser ce qui reste du modĂšle «7-1», vous enregistrez les abstracts , les components , la layout et la base des dossiers.
  • Si vous dĂ©cidez de vous dĂ©brouiller avec un seul grand dossier, tous les fichiers contenant des fragments de style, ainsi que le fichier main.scss , tombent dans ce dossier. Cela peut ressembler Ă  ceci:

 sass/ _animations.scss _base.scss _buttons.scss _header.scss ... _variables.scss main.scss 

Que choisir exactement dépend de vos préférences.

Ici, si vous ĂȘtes inspirĂ© par l'idĂ©e d'utiliser SCSS, vous pouvez avoir une question sur la façon d'utiliser ces styles, car les navigateurs ne les prennent pas en charge. En fait, c'est une bonne question qui nous amĂšne Ă  la derniĂšre Ă©tape de notre conversation, Ă  la compilation de SCSS en CSS.

Compilation de SCSS en CSS


Pour convertir le code SCSS en CSS, vous aurez besoin de la plateforme Node.js et du gestionnaire de packages NPM (ou Yarn ).

Nous utiliserons le node-sass , qui nous permet de compiler des fichiers .scss fichiers .scss . Il s'agit d'un outil en ligne de commande, il est facile à utiliser. À savoir, l' node-sass ressemble à ceci:

 node-sass <input> <output> [options] 

De nombreuses options sont disponibles ici. Nous nous concentrerons sur deux:

  • L'option -w vous permet de surveiller un dossier ou un fichier. Autrement dit, node-sass gardera une trace des modifications dans le code et, lorsqu'elles se produisent, compilent automatiquement les fichiers en CSS. Cette fonctionnalitĂ© est trĂšs utile pendant le processus de dĂ©veloppement.
  • L'option --output-style dĂ©termine le style du fichier CSS de sortie. Plusieurs options sont disponibles ici: nested , expanded , compact , compressed . Nous utiliserons cette option pour construire un fichier CSS fini.

Si vous ĂȘtes une personne curieuse (j'espĂšre que c'est le cas, car la curiositĂ© n'est que pour le bĂ©nĂ©fice du dĂ©veloppeur), alors vous serez probablement intĂ©ressĂ© par la documentation du node-sass .

Nous avons donc décidé des outils, maintenant la chose la plus simple reste. Afin de convertir SCSS en CSS, vous devez suivre ces étapes:

Créez un dossier de projet et accédez-y:

 mkdir my-app && cd my-app 

Initialisez le projet:

 npm init 

Ajoutez le package node-sass au projet:

 npm install node-sass --save-dev 

Créez un fichier index.html , des dossiers de styles, main.scss fichier main.scss :

 touch index.html mkdir -p sass/{abstracts,base,components,layout} css cd sass && touch main.scss 

Ajoutez ce qui suit au fichier package.json :

 { ... "scripts": {   "watch": "node-sass sass/main.scss css/style.css -w",   "build": "node-sass sass/main.scss css/style.css --output-style compressed" }, ... } 

Ajoutez le lien menant au fichier CSS compilé dans la balise head du fichier index.html :

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="css/style.css"> <title>My app</title> </head> <body> <h1 class="heading">My app</h1> </body> </html> 

C’est tout. Maintenant que vous travaillez sur le projet, exĂ©cutez la npm run watch et ouvrez le fichier index.html dans votre navigateur. Pour rĂ©duire CSS, exĂ©cutez la npm run build .

Utilitaires supplémentaires


▍ Rechargement de page interactif


Vous souhaiterez peut-ĂȘtre organiser un rechargement de page interactif pour augmenter la productivitĂ©. C'est plus pratique que de recharger manuellement index.html . Voici comment procĂ©der:

Installez le package live-server (notez qu'il est installé globalement):

 npm install -g live-server 

Ajoutez le package npm-run-all , selon le projet, qui vous permet d'exĂ©cuter plusieurs scripts en mĂȘme temps:

 npm install npm-run-all --save-dev 

Ajoutez ce qui suit Ă  package.json :

 { ... "scripts": {   "start": "npm-run-all --parallel liveserver watch",   "liveserver": "live-server",   "watch": "node-sass sass/main.scss css/style.css -w", }, ... } 

Maintenant, aprÚs avoir exécuté la commande npm run start , vous, en train de travailler sur le projet, verrez instantanément les modifications qui y sont apportées sans recharger la page manuellement.

Package package autoprefixer


A ce stade, vous disposez d'un environnement de développement personnalisé, ce qui est trÚs bien. Parlons maintenant des outils de construction d'un projet, et en particulier du package autoprefixer . Il s'agit d'un outil (nous parlons d'un plugin postcss) qui analyse le code CSS et ajoute des préfixes de fournisseurs de navigateur aux rÚgles CSS en utilisant les données de Can I Use .

Lors de la création du site, le programmeur peut utiliser de nouvelles fonctionnalités qui ne sont pas entiÚrement prises en charge par tous les navigateurs. Les préfixes de navigateur visent à résoudre un certain nombre de problÚmes, notamment le développement d'applications Web inter-navigateurs.

Le code avec les préfixes du navigateur ressemble à ceci:

 -webkit-animation-name: myAnimation; -moz-animation-name: myAnimation; -ms-animation-name: myAnimation; 

Il est facile de remarquer que l'écriture d'un tel code est trÚs fastidieuse. Afin de faciliter la tùche d'assurer la compatibilité de notre code CSS avec différents navigateurs, sans compliquer le projet, nous utiliserons le package autoprefixer . Ici, vous devrez effectuer les étapes suivantes:

  • Nous compilons tous les fichiers SCSS dans un seul fichier CSS principal.
  • Ajoutez les prĂ©fixes du navigateur Ă  ce fichier Ă  l'aide du autoprefixer .
  • Compressez ce fichier CSS.

Il s'agit en général de la derniÚre étape des travaux sur le projet. Voici donc ce que vous devez faire pour utiliser le autoprefixer :

Ajoutez deux dépendances au projet - postcss-cli et autoprefixer :

 npm install autoprefixer postcss-cli --save-dev 

Ajoutez le code suivant Ă  package.json et modifiez le script de build :

 { ... "scripts": {   "start": "npm-run-all --parallel liveserver watch",   "liveserver": "live-server",   "watch": "node-sass sass/main.scss css/style.css -w",   "compile": "node-sass sass/main.scss css/style.css",   "prefix": "postcss css/style.css --use autoprefixer -o css/style.css",   "compress": "node-sass css/style.css css/style.css --output-style compressed",   "build": "npm-run-all compile prefix compress" ... } 

npm run build , CSS-, . , , . — , , .

, ,

Résumé


, CSS, , , CSS-, , .

Chers lecteurs! -?

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


All Articles