Alsacreations.com - Actualités - Archives (juillet 2022)

Les dernières actualités d'Alsacreations.com

Le: 19 07 2022 à 11:30 Auteur: Raphael

Les styles CSS doivent leur nom à la Cascade, qui est un bien joli et complexe algorithme tenant compte de nombreux paramètres tels que l'origine des styles, la spécificité des sélecteurs ainsi que leur ordre d'apparence.

La Cascade, c'est l'essence même de CSS. C'est ce qui fait son utilité, sa beauté… et c'est aussi le pire cauchemar des intégratrices et intégrateurs.

La Cascade, c'est ce qui fait que nos paragraphes arboreront une chatoyante couleur hotpink avec les déclarations suivantes :

<p class="kiwi">Coucou !</p>
p {color: tomato;}
p {color: hotpink;}

Mais quel est le problème au juste ?

Dans un monde idéal, l'intégration HTML / CSS est prise en compte en amont du projet, en se donnant les ressources adéquates et les compétences nécessaires. Ce n'est bien évidemment pas un domaine que l'on traite à la légère, après le budget alloué à la communication, au SEO, aux développements "lourds" etc. en se disant que "après tout ce n'est que du CSS, même pas un vrai langage".

Mais ça c'est dans un monde idéal.

Dans un vrai projet, on récupère du code produit par des anciens stagiaires disparus ou par des frameworks de version obsolète, on a totalement oublié de s'appuyer sur une convention de nommage, on intègre avec un onglet de Stackoverflow toujours ouvert dans un coin, et on peste contre le monde entier à tenter d'écraser des styles avec !important (voire des !veryimportant ah non ça c'était une blague).

Qui n'a jamais utilisé !important me jette la première <br> !

Le vrai projet, c'est celui où l'on passe toujours trop de temps à comprendre pourquoi nos paragraphes sont chocolate et pas hotpink dans ce cas là :

p {color: tomato;}
.kiwi {color: pink;}
div p:first-child {color: chocolate;}
p.kiwi {color: hotpink;}

Où les Cascade Layers entrent en jeu

Les spécifications CSS ont introduit une règle-at @layer permettant de redéfinir l'ordre et la priorité dans la cascade CSS à l'aide de "layers" (couches).

Le principe général est simple : l'ordre de déclaration des layers (Layers Order) est prioritaire sur la spécificité des sélecteurs.

Ainsi, dans l'exemple qui suit, les paragraphes prendront la couleur hotpink car leur couche est déclarée en dernier.

@layer reset {
  p {color: olive;}
  .kiwi {color: pink;}
  div p:first-child {color: chocolate;}
}
@layer base {
  p {color: hotpink;}
}

Un tiramisu pour représenter les couches

Déclarer des layers

Il existe plusieurs moyens de créer des couches de styles : la règle @layer avec styles associés, la même sans styles, ou l'import de fichiers de styles externes.

Règle @layer avec styles associés

On déclare la couche via @layer en lui donnant un nom (optionnel) et on y applique des règles CSS.

@layer reset {
  /* ici les règles CSS de la couche reset */
}
@layer base {
  /* ici les règles CSS de la couche base */
}

Règle @layer sans styles

On déclare la couche via @layer vide.

@layer reset;
@layer base;

Pour info, cet exemple est équivalent à cette syntaxe :

@layer reset, base;

Cette formulation, sans styles associés, n'a d'autre but que de déclarer un ordre précis dans les couches.

Import de styles externes

La notion de layer peut être associée à la règle @import :

@import url("reset.css") layer(reset);

En plus de l'import via @import, le W3C travaille sur une version importée avec l'élément <link>.

Concrètement cela représente un moyen très simple de pouvoir :

  • Importer les styles d'un framework tel que Boostrap (au hasard) au sein de layers, donc avec une spécificité moindre
  • Pouvoir redéfinir ses propres styles sans se soucier du poids des sélecteurs Boostrap ni même des !important… et si j'évoque ce framework en particulier, ce n'est pas tout à fait anodin (oui, il y a bien 1307 !important dans ce seul fichier CSS)
@import url("bootstrap.css") layer(framework);

Cake sucré de marque Layers of Joy

En pratique

Le postulat de base est que chaque layer est prioritaire sur le layer déclaré avant lui. L'ordre est donc primordial.

Dans l'exemple qui suit, tous les paragraphes seront de couleur hotpink même s'ils disposent de la classe .kiwi car le layer base est déclaré après reset :

@layer reset {
  p.kiwi {color: tomato;}
}
@layer base {
  p {color: hotpink;}
}

Étendre des styles aux layers existants

Il est possible d'ajouter des styles à une couche existante, simplement en reprenant le nom du layer déjà créé :

@layer reset {
  p.kiwi {color: tomato;}
}
@layer base {
  p {color: hotpink;}
  h1 {color: olive;}
}
@layer reset {
  h1 {color: chocolate;}
}

Dans cet exemple, les styles sur h1 sont ajoutés à ceux déjà présents dans la couche reset.

Notez qu'étendre des layers ne modifie pas l'ordre originel (et donc l'application) des layers. En clair, ici la couleur des titres h1 sera olive car le layer base est déclaré après reset.

Une bonne pratique consiste à définir dans un premier temps l'ordre de toutes les couches en une règle raccourcie (ex. @layer reset, base;), puis d'étendre les styles de chacun des layers, ainsi il n'est pas possible de se tromper dans l'ordre d'application des couches.

Dans l'exemple suivant, je souhaite prioriser les styles de la couche base, je vais donc commencer par indiquer l'ordre à respecter.

Ici, malgré ma maladresse (j'ai étendu les styles base puis ceux de reset), ce sont bien les styles de base qui sont prioritaires et s'appliquent. Les paragraphes seront hotpink :

@layer reset, base;

@layer base {
  p {color: hotpink;}
}

@layer reset {
  p {color: olive;}
  .kiwi {color: tomato;}
}

Cake sucré de marque Multi Layers

Particularité des styles sans layer

Cela peut paraître curieux, mais les styles sans layer sont appliqués en priorité.

Ainsi, dans l'exemple qui suit les paragraphes seront de couleur hotpink :

p {color: hotpink;}

@layer reset {
  p {color: olive;}
  p.kiwi {color: tomato;}
}

Imbrication de layers

On peut imbriquer les Cascade Layers de cette manière :

@layer framework {
  @layer reset {

  }
}

Il est ensuite possible d'étendre les styles de ce layer en y faisant référence ainsi :

@layer framework.reset {
  /* j'étends les styles dans le layer reset dans framework */
  p { color: hotpink; }
}

Compatibilité et mot de la fin

Bonne nouvelle : CSS Cascade Layers est une spécification dont le support est relativement large. À l'heure où cet article est rédigé, seules les anciennes versions de Safari et Samsung Internet sont à la traîne (si on ne tient pas compte d'Internet Explorer bien sûr). Cela signifie que cette fonctionnalité peut très vite être utilisable en production.

Support de CSS Cascade Layer sur les navigateurs web à partir de caniuse.com

Et vous, qu'en pensez-vous ? Êtes-vous aussi impatient que moi de pouvoir bénéficier de cette spécification afin d'assainir radicalement tous les anciens projets web que l'on maintient tant bien que mal ?

Publié par Alsacreations.com

Le: 13 07 2022 à 10:45 Auteur: Arteast

On l'a vu dans l'article "Pourquoi écrire du Twig dans WordPress ?", Timber est une excellente dépendance pour WordPress faite pour les développeurs.

J'aimerais faire le lien avec l'article "Préparer un thème WordPress pour l'internationalisation", car la syntaxe n'est pas forcément évidente si vous êtes habitués à l'écriture standard de WordPress.

Les bases

Dans l'ensemble, rien de bien plus compliqué qu’avec PHP hormis la syntaxe. On utilise toujours la même fonction WordPress qui est aussi disponible dans Timber.

Voilà un exemple simple avec PHP :

<?php echo __( "Voir toutes les actualités", "textdomain" ); ?>

Et voilà son équivalent avec Timber :

{{ __( "Voir toutes les actualités", "textdomain" ) }}

Jusqu’ici tout va bien, si vous avez l’habitude d’écrire en Twig c’est la même chose.

Abordons maintenant un cas plus spécifique.

Gérer les singuliers et les pluriels

Dans cette partie, on utilisera l'exemple de la barre de recherche, qui est un composant que l'on retrouve fréquemment sur beaucoup de sites et qui est naturellement accompagnée d'une page de résultats, sur laquelle on retrouve une phrase récapitulant le nombre de résultats trouvés et la requête faite par l'utilisateur.

Le formulaire de recherche d'alsacreations.com

Cette dernière est souvent sous la forme : "X résultat(s) trouvé(s) pour le mot Y."

Ce qui induit qu'en fonction du nombre de résultats trouvés, cette phrase peut être au pluriel. Comme toujours, il y a plusieurs méthodes pour réaliser cela et je divulgâche, mais certaines de ces méthodes sont meilleures que d'autres sur plusieurs points.

Première méthode

En tant que développeur, on peut être tenté de gérer l'affichage avec une condition.

Par exemple :

  • Si le résultat de ma recherche est supérieur à 1, j'affiche le pluriel, sinon j'affiche le singulier.
  • J’utilise la fonction sprintf avec les spécificateurs adéquats respectivement pour le nombre de résultats et le terme de recherche.

En PHP, cela donnerait :

<?php if( $search_result > 1 ) : ?>

  <?php
    sprintf(
      __( "%d résultats trouvés pour le mot \"%s\".", "textdomain" ),
        $search_result,
        get_search_query()
    );
  ?>

<?php else : ?>

  <?php
    sprintf(
      __( "%d résultat trouvé pour le mot \"%s\".", "textdomain" ),
        $search_result,
        get_search_query()
      );
  ?>

<?php endif; ?>

Et avec Timber :

{% if search_result|length > 1 %}

  {{
    __( "%d résultats trouvés pour le mot \"%s\".", "textdomain")|format(
      search_result|length,
      fn('get_search_query')
    )
  }}

{% else %}
  {{
    __( "%d résultat trouvé pour le mot \"%s\".", "textdomain" )|format(
      search_result|length,
      fn('get_search_query')
    )
  }}

{% endif %}

C’est la même chose, excepté que l’on remplace un appel de fonction par un filtre.

On y retrouve :

  • Le filtre length sur la variable search_result renvoie le nombre d'éléments.
  • La fonction __() pour les traductions avec le bon textdomain
  • Le filtre format qui est l’équivalent de la fonction sprintf en PHP
  • fn() ou function() qui permet d’utiliser une fonction WordPress ou PHP

Avec cette méthode, si search_result est supérieur à 1, on obtiendra :

2 résultats trouvés pour le mot Burger.

Sinon :

1 résultat trouvé pour le mot Burger.

Parfait, le résultat est comme attendu. Ça fonctionne !

Dans notre outil de traduction (Poedit), on retrouve bien les chaînes de caractères à traduire. Cependant, il y a une chaîne pour gérer le singulier et une pour gérer le pluriel.

Les chaines de traduction dans Poedit

Pourquoi ça ne va pas ?!

  • On se retrouve avec deux traductions à produire, alors que c’est potentiellement la même phrase.
  • S'il y a des cas similaires à traiter sur le site, on aura un fichier de traduction long comme le bras, qui contient pleins de doublons de phrases.
  • Si le fichier doit être fourni à une tierce personne pour la traduction, cela manquera de contexte pour traduire correctement.

Il existe des fonctions faites pour ce genre de cas !

La bonne méthode

Pour avoir des traductions singulier/pluriel propres et optimisées, on utilise la fonction WordPress _n(), qui est un tout-en-un.

Il suffit de lui passer la valeur qui sert de référence et elle s'occupera de choisir d'afficher le singulier ou le pluriel.

Toujours dans l'exemple de page de résultats de recherche, voici comment l'utiliser avec PHP :

<?php
  sprintf(
    _n(
      "%d résultat trouvé pour le mot \"%s\".",
      "%d résultats trouvés pour le mot \"%s\".",
      $search_result,
      "textdomain"
    ),
    $search_result,
    get_search_query()
  );
?>

Et son équivalence avec Timber :

{{
  __(
    _n(
      "%d résultat trouvé pour le mot \"%s\".",
      "%d résultats trouvés pour le mot \"%s\".",
      search_result|length,
      "textdomain"
    )|format(
      search_result|length,
      fn('get_search_query')
    )
  )
}}

Mais c’est plus imbriqué, plus dur à lire/écrire et la finalité est la même ! Alors ça change quoi ? 🤔

Le résultat dans l'outil de traduction est complètement différent !

Un exemple de gestion correcte des pluriels dans Poedit

Pourquoi c’est mieux ? Pourquoi privilégier cette méthode ?

  • Le singulier et le pluriel se retrouvent dans le même champ pour la traduction
  • On apporte plus de contexte et de compréhension
  • On obtient un fichier de traduction optimisé et propre

Et voilà ! Vous avez une bonne pratique supplémentaire à intégrer dès le début du développement de votre thème WordPress avec Timber !

À bientôt pour un prochain article. 🙂

Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com