openSUSE 13.2, BTRFS and LUKS

In this article, I explain how to install openSUSE 13.2 with full disk encryption.

My configuration

/dev/sda1 512MB ext2 mounted on /boot
/dev/sda2 [remaining space] LUKS container (named "cryptroot")
	LVM (named "lvmroot")
		rootvol	15GB BTRFS mounted on /
			var
		homevol	[remaining space] BTRFS mounted on /home

I do not use swap, but a swap partition could be easily created as a LVM volume.

Prepare the bootable images

We need Gparted live on a CD and openSUSE on a DVD.

Step 1: Partition with Gparted live

Boot on the Gparted live CD.

Using Gparted, make the partitions /dev/sda1 (512 Mb) and /dev/sda2 (remaining space).

Open a terminal, then create the LUKS container (and give the passphrase):

sudo cryptsetup luksFormat /dev/sda2
sudo cryptsetup luksOpen /dev/sda2 cryptroot

Then, create the LVM container on the LUKS container:

sudo pvcreate /dev/mapper/cryptroot
sudo vgcreate lvmroot /dev/mapper/cryptroot

Finally, create the volumes in the LVM container:

sudo lvcreate -L 15G lvmroot -n rootvol
sudo lvcreate -l +100%FREE lvmroot -n homevol

We didn’t format the volumes here. It will be done during the installation of openSUSE.

Step 2: Install openSUSE

Boot on the openSUSE DVD.

The installation process automatically detects the LUKS container and proposes to enter the passphrase.

On the “Partition” step, the suggested configuration is to remove the LUKS container and create a fresh partition. This is not our case. So, click on Create the partitions configuration → Custom partitioning (expert):

  • The partition /dev/sda1: format as ext2, mount at startup as /boot.
  • The volumes rootvol and homevol: format as BTRFS, mount at startup as / and /home. For my SSD, I use the following mount options: noatime,ssd,autodefrag,compress=lzo,discard,space_cache. In the volume rootvol, I replaced all the default subvolumes by a single subvolume var.

Cinq mauvaises raisons de quitter WordPress pour Joomla!

J’ai récemment lu un article traduit qui prête à WordPress cinq faiblesses imaginaires.

J’ai pratiqué Joomla! en 2009 et 2010, à l’époque en version 1.5, avant de passer à WordPress. Les deux CMS suivent un chemin différent et il me semble que le lecteur qui n’aurait pas pratiqué les deux gagnerait à se faire une idée des différences bien réelles.

Joomla est un CMS généraliste centré sur son panneau d’administration. WordPress est un moteur de blog doté d’une API ouverte. Et cela change tout.

Prenons une opération simple. Nous souhaitons ordonner la liste d’articles d’une rubrique par ordre alphabétique. Sous Joomla, cela consiste à se connecter au panneau d’administration et à cliquer au bon endroit dans l’IHM. Joomla en effet stocke en base l’ordonnancement des rubriques au même titre qu’une ribambelle d’options servant à paramétrer le site.

Voyons l’opération équivalente dans WordPress. Aucun bouton n’existe pour cela dans le panneau d’administration. La procédure habituelle demande des connaissances en PHP. Voici comment faire. Dans le thème du site, dupliquer le fichier de template category.php et renommer la copie en suffixant par l’identifiant de la catégorie, par exemple : category-123.php. Puis éditer la copie. Afin d’ordonner sur le titre en alphabétique, insérer la ligne suivante juste après l’appel à get_header() dans le code PHP :

query_posts("$query_string&orderby=title&order=asc");

On comprend que Joomla et WordPress ne s’adressent tout simplement pas au même public. Joomla est préféré par les experts cliqueurs ou les utilisateurs finaux qui souhaitent, sans investir trop de temps dans la technique, construire eux-même leur site. WordPress en dehors du blog n’est utilisable que par des développeurs.

Je suis intégrateur et développeur Web. Je préfère WordPress car :

  1. En tant que développeur, programmer vaut mieux que cliquer. Je travaille plus finement et plus rapidement avec WordPress ;
  2. Le panneau d’administration de WordPress est apprécié de mes utilisateurs finaux. Celui de Joomla leur faisait peur.

Et voilà deux bonnes raisons de choisir WordPress plutôt que Joomla Ce sont de vraies raisons. Je ne résiste pas à reprendre les cinq mauvaises raisons de l’article cité plus haut. L’article prétend que :

  1. Joomla aurait plus d’extensions et plus de fonctionnalités, citons Joomla contre ce mensonge : 11 713 extensions WordPress, 6 745 pour Joomla. WordPress fait du commerce en ligne ni plus ni moins que Joomla. Le point est pour WordPress.
  2. Le panneau d’administration de Joomla fait plus de choses que celui de WordPress. Cet argument a déjà eu sa réponse ici et en ce qui concerne l’ergonomie pour un utilisateur final qui ne ferait pas lui-même son site Web, le point est pour WordPress.
  3. Sur la rapidité de l’entraide j’aimerais juste que l’auteur essaie pour voir, quant à moi je n’ai jamais eu besoin d’autre chose que l’aide en ligne. Ce point n’existe pas.
  4. Ici l’auteur cite une véritable différence entre Joomla et WordPress. WordPress n’a pas de version majeure alors que Joomla les collectionne. Les plugins et les thèmes de Joomla sont alors régulièrement bons pour la poubelle tandis que les évolutions de WordPress se passent en douceur. Le point est pour WordPress.
  5. Sur le temps qu’il faut pour concevoir un site Web avec Joomla, mais de qui parle-t-on ? Un intégrateur est aussi un développeur Web, il ira donc plus vite avec WordPress. Un utilisateur final souhaitant se débrouiller seul ne pourra tout simplement pas faire autre chose que du blog avec WordPress. S’il s’agit de rapidité de travail pour le professionnel, le point est pour WordPress.

Cela nous fait quatre à zéro pour WordPress.

L’objet de cet article était de réagir alors je m’arrête là. Mais des faiblesses de WordPress, il en existe pourtant : un code PHP procédural à l’ancienne, des performances douteuses, une configuration des URLs limitée, un mécanisme d’upload trop orienté blog… Et surtout l’impossibilité de configurer les groupes d’utilisateurs et les droits d’accès, ce qui est à mon avis le défaut le plus bloquant pour les projets de grandes tailles.

Les ORM, c’est mal

La fausse route des ORM

Les mapping objets-relationnels sont une erreur. La conception du schéma d’une base de données obéit à des règles différentes de celles de la programmation à objets. Mieux vaut concevoir ses objets avec une approche « métier », je veux dire que les objets devraient être conçus en fonction de ce que le logiciel doit faire et non pas en fonction des règles de normalisation suivies par la base de données.

C’est un peu comme si la boutique devait coupler ses étalages avec les rayons de l’entrepôt. Mais les étalages sont gouvernés par le marketing alors que les entrepôts sont organisés par la logistique. Entre le responsable du marketing et celui de la logistique, qui gagnera ? Lorsque Hibernate ou EclipseLink génère la structure de la base de données au travers d’un code DDL, c’est le marketing qui gère les entrepôts. C’est l’assurance d’une logistique lente et inefficace.

Si l’ORM est une factorisation automatisée du code source, elle est surtout la factorisation du développeur paresseux et elle est loin d’être la plus élégante.

SQL versus ORM : une inversion des bonnes pratiques

Un mapping objet sert à naviguer d’objet en objet. Je sais qu’il est possible de faire autrement mais l’ORM sert à cela. Chaque objet est chargé avec l’intégralité d’une ligne d’une table. Et peu importe que telle colonne ne soit pas utilisée par telle partie du programme, l’objet du mapping chargera toutes les colonnes.

Par comparaison, le SQL sert à sélectionner les valeurs des cellules à utiliser et uniquement celles-là. Le SQL correspond bien au besoin du programmeur car il est rare d’utiliser simultanément toutes les colonnes d’une table dans une même portion du programme.

Certes les ORM proposent tous une solution palliative, une sorte de sous-dialecte SQL avec lequel il devient possible d’extraire des valeurs sans passer par les objets. Il s’agit ici d’une inversion des bonnes pratiques. Bien utiliser un ORM c’est d’abord utiliser les objets du mapping, puis éventuellement pratiquer le sous-dialecte SQL dans les cas qui le justifient. Bien utiliser le SQL c’est, toujours, en une fois, charger les données dont on a besoin, toutes les données dont on a besoin et seulement les données dont on a besoin.

L’élégance et la performance sont les fils conducteurs du SQL. L’ORM n’a que faire de l’élégance et se passerait bien des catastrophes en performance que lui inflige la réalité.

Le débat du SQL versus les ORM porte alors non pas sur ce qu’on peut faire – en vérité on peut faire des objets et des tableaux avec un ORM autant qu’avec du SQL – mais quelles sont les bonnes pratiques en matière de bases de données.

Le cas de PHP

Au-delà des considérations générales, l’utilisation systématique d’objets en PHP a un impact négatif sur les performances. Selon moi cela suffit à changer de perspective par rapport à d’autres langages : on ne devrait pas coder en PHP comme on code en Java. Le cœur de PHP est le tableau associatif PHP. Et ça tombe bien car il est dans la nature du SQL de ramener des tableaux. Alors pour la simplicité, l’élégance et la performance, restons-en à l’essentiel. Le couple « requête SQL – tableau PHP » est le meilleur choix partout où il s’avère suffisant.

Le logiciel libre est l’avenir du logiciel

Nota. – Cet article est aussi une réaction à la remarque de Philippe Scoffoni : « Je défends régulièrement l’idée que les logiciels libres ne devraient pas être portés par des entreprises. »

Brevets et droits d’auteur

Les brevets et les droits d’auteurs sont des interdictions de dupliquer des créations numériques, ceci dans le but de donner à ces dernières des propriétés économiques similaires aux créations du monde physique.

Une création numérique est par nature dupliquable. Les brevets et les droits d’auteurs vont donc contre la nature des choses. Parions que leur usage déclinera.

Les trois niveaux d’accès aux produits numériques

Dans le contexte légal actuel, les interdictions de copies sont le cas normal. Aussi, protéger des créations numériques contre ces interdictions implique de mentionner explicitement que la copie est libre. C’est ainsi que le secteur logiciel a vu apparaitre les « logiciels libres ».

L’appellation « logiciel libre » inclut trois libertés : la liberté de copier et d’utiliser le logiciel, la liberté de regarder le code source (avant compilation en code machine), c’est-à-dire de voir comment le logiciel est fait, puis la liberté de réutiliser ce code source pour fabriquer une variante ou un nouveau logiciel.

À mon sens seule la liberté de copier est véritablement inhérente aux produits numériques. Le code source est au logiciel ce que la recette de cuisine est au biscuit : sauf s’il a un intérêt à la publier, le créateur conservera secrète sa recette et vendra les biscuits. Le concurrent tentera éventuellement de reconstituer la recette en analysant le biscuit, l’opération est difficile et parfois même moralement condamnable, mais il est heureux qu’il ne soit pas possible de la rendre illégale. Dans le secteur du logiciel, l’opération équivalente se fait au moyen d’un désassembleur et est tout aussi difficile, éventuellement moralement condamnable, et… malheureusement illégale.

Attardons-nous sur les deux autres libertés : celle de regarder le code source (la recette de fabrication) et celle de modifier ce code source pour créer un nouveau produit. Ces deux libertés sont couplées car il n’y aurait pas grand sens à faire l’effort de comprendre la fabrication sans en tirer un profit quelconque. Et cela est également vrai en dehors du secteur logiciel : l’écrivain publie au format PDF ou epub et conserve pour lui le fichier originel du traitement de texte, le graphiste publie un fichier image et non pas le fichier Photoshop, etc.

Aussi on peut distinguer trois niveaux d’accès aux créations numériques :

  1. les produits numériques dont le code source (les fichiers de travail) est gardé secret (mais ils restent copiables et utilisables) ;
  2. les produits numériques dont le code source est publié et réutilisable (en plus d’être copiables et utilisables) ;
  3. l’interdiction de copie par des artifices juridiques contre nature.

J’ai mis l’interdiction de copie en dernier car elle est vouée à l’obsolescence. Seules les deux premières options sont naturelles, mais alors les anciens modèles économiques hérités du monde physique ne fonctionnent plus.

Les créateurs individuels dans l’économie numérique

Un modèle qui reste largement à développer est le don de charité. En France le mot « charité » est souvent employé à tort dans le sens de « pitié ». Si on lui donne son véritable sens, à savoir, l’« amour », le véritable amour désintéressé envers autrui, et cela inclut la reconnaissance en vérité, il est crédible que la rémunération puisse fonctionner. Qui ne paierait pas une bière ou un café au bon gars qui a fabriqué tel outil « dont je me sers chaque jour » ou telle œuvre musicale « que j’apprécie tant » ? Il y a certainement un créneau économique pour la charité.

À titre personnel j’attends l’organisme qui se chargera de simplifier le paiement des dons et de gérer la distribution vers les créateurs, je lui confierai la rémunération de mes propres travaux.

Mais, pour de multiples bonnes raisons, la rémunération par charité s’applique à des individus plus qu’à des entreprises.

Les entreprises à but lucratif dans l’économie numérique

Le mode de rémunération d’un producteur numérique n’est pas celui d’un producteur industriel. Le produit industriel a par nature un cout de duplication et l’industriel est précisément focalisé sur sa diminution pour vendre plus d’exemplaires ou avec plus de marge. Le produit logiciel est au contraire multipliable sans frais et son producteur est alors focalisé sur l’amélioration du produit plus que sur la logistique.

Vendre un produit numérique

Si les biscuits industriels devenaient multipliables sans cout, le producteur de biscuits n’en vendrait qu’un puisque ses clients se chargeraient ensuite de le dupliquer. L’éditeur d’un logiciel est dans cette situation folle du producteur de « biscuits multipliables » et plutôt que de vendre les biscuits il ferait mieux de vendre des « abonnements à des améliorations de biscuits ».

Plaçons-nous dans le cas où le client est lui-même une entreprise. Puisque la duplication n’a aucune valeur ajoutée c’est l’amélioration qui en a. Un client rechignera toujours à payer trente exemplaires du même logiciel pour ses trente employés. Il est prêt en revanche à payer pour utiliser « le même produit mais en mieux ». On pourrait penser que, si le produit est dupliquable, le client sera tenté de se fournir chez son voisin et ainsi ne rien payer. Mais quelle garantie d’authenticité (et donc de sécurité) aurait-il alors ? Et qu’en serait-il du retard ou de l’incertitude sur les mises à jour ? Même pour les besoins les plus communs, si une entreprise utilise un logiciel développé à l’extérieur de l’entreprise, c’est précisément qu’elle ne souhaite pas gérer en interne la création ou l’évolution de ce logiciel. Un éditeur de logiciel pourrait alors, par contrat, interdire à ses clients de copier le logiciel en dehors du cadre de l’entreprise. Dans la plupart des cas cette condition serait respectée puisque le client : 1. trouve un intérêt à conserver de bons rapports avec son fournisseur dans la mesure où il a besoin des mises à jour, 2. ne trouve pas d’intérêt à diffuser le logiciel en externe, cela n’ayant pas de rapport avec son activité.

La vente d’abonnements de mises à jour est peut-être plus difficilement applicable aux particuliers. Quoique avec une offre et des tarifs adaptés, qui sait ?

Ce mode de rémunération est plus logique avec un code source conservé secret. En effet, les concurrents plus que les clients et les partenaires verraient un intérêt à regarder et réutiliser le code source.

Vendre un service sur le Web

Dans le cas d’un service mis à disposition sur le Web (« en ligne »), seule une petite partie du logiciel est récupérée par le client. Aussi la copie du produit complet est impossible. La vente d’un service sur le Web obéit donc plutôt aux règles de l’économie traditionnelle.

Certes, il se trouve que les utilisateurs du Web refusent de payer. La cause est ici dans les habitudes liées à Internet – car Internet est rempli de bénévoles et c’est ce qui le rend fantastique – et non pas dans la nature numérique des choses.

Un mot ici sur les publicités. Une manière répandue de se rémunérer sur un service gratuit est de s’appuyer sur l’économie des biens physiques en utilisant les biens numériques comme panneaux publicitaires. C’est notamment ainsi que se financent certaines messageries numériques gratuites et de nombreux sites Web. J’avoue que je crois assez peu à une généralisation de ce système sur le long terme. Le Web ne restera pas une annexe de l’économie des biens physiques.

L’aboutissement du logiciel est le logiciel libre

Une image. La production à but lucratif d’un logiciel ressemble à une échappée dans une course cycliste : 1. Le producteur crée un logiciel en avance dans son domaine, il le diffuse en conservant secret le code source. 2. Le producteur innove sans cesse pour vendre et se maintenir devant la concurrence. 3. Au fur et à mesure que la qualité des logiciels concurrents se rapprochent, le choix devient, libérer le code source ou devenir un acteur marginal.

Au passage, dès la première étape le producteur peut trouver un intérêt à libérer certaines briques de son produit, cela lui permet de mutualiser le développement de ces briques avec d’autres acteurs. Par exemple Cassandra fut libéré par Facebook et passé sous le contrôle de la fondation Apache, avant d’être adopté par Twitter.

Et voilà comment au bout du compte le logiciel libre est l’avenir du logiciel.

PHP : Au revoir Aptana/Eclipse, bonjour NetBeans !

Cela fait longtemps que Aptana (ou Eclipse avec le plugin PDT) présente des lacunes gênantes en tant que IDE pour PHP et ce n’est pas la première fois que je tente un passage à NetBeans. Cette fois-ci est la bonne, principalement parce que j’ai retrouvé des équivalents de tous les raccourcis clavier d’Aptana qui m’étaient nécessaires. Il y a un an certains n’existaient pas, ou bien avais-je mal cherché ?

Pour ceux que ça intéresserait, voici un comparatif des fonctionnalités qui me sont essentielles sur les dernières versions d’Aptana et de NetBeans : Aptana 3.3.1 et NetBeans pour PHP 7.2.1.

Les fonctionnalités communes

Les deux IDE reconnaissent la syntaxe des balises HTML 5 et des propriétés CSS 3. Les deux disposent de la panoplie standard des raccourcis clavier pour éditeurs de code source : CTRL HAUT et BAS (défilement de l’éditeur), CTRL GAUCHE et DROITE (équivalent des boutons « précédent » et « suivant » dans un navigateur), CTRL ESPACE (pour forcer les propositions d’auto-complétion), etc.

Certaines fonctionnalités similaires sont accessibles différemment :

Action Aptana / Eclipse NetBeans
Rechercher la sélection CTRL K CTRL F3
Aller à la déclaration F3 CTRL B
Supprimer une ligne CTRL D CTRL E
Aller au numéro de ligne CTRL L CTRL G
Ouvrir un fichier CTRL T ou MAJ CTRL R ALT MAJ O
La synchronisation du fichier sélectionné dans la fenêtre Projets avec celui édité. Bouton dans la fenêtre Projets Menu contextuel de l’éditeur

NB. Sur les deux plateformes les raccourcis sont configurables.

À l’avantage de NetBeans

Des fonctionnalités de NetBeans que Aptana et Eclipse n’implémentent pas :

  • La syntaxe PHP 5.4 est reconnue (Aptana étant resté bloqué sur PHP 5.3).
  • Les commentaires PHPDoc sont accessibles au survol des méthodes lorsqu’on presse la touche CTRL. Sous Aptana, seules les fonctions standards sont documentées.
  • NetBeans vient avec une fonctionnalité de refactoring pour PHP.
  • Le débogage en PHP est un gros atout (que je n’utilise pas).
  • L’IDE est globalement plus léger : plus réactif, plus rapide à charger. Il consomme moins de mémoire vive, il tient sur moins d’espace disque qu’Aptana ou Eclipse.

Toujours à l’avantage de NetBeans, des bogues ou défauts de Aptana/Eclipse :

  • Sous Eclipse et Aptana, un bogue empêche de commenter/décommenter plusieurs lignes à la fois sur les claviers azerty.
  • Sous Aptana, l’outil de marquage automatique des occurrences d’une variable, méthode ou classe ne fonctionne pas lorsque le curseur est positionné sur la déclaration d’une propriété dans une classe.
  • Sous Aptana, dans la fenêtre « Outline » (équivalent de « Properties »), les éléments listés sont repliés par défaut et cette fenêtre est par conséquent sous-utilisée.

À l’avantage d’Aptana/Eclipse

Des fonctionnalités propres à Aptana et Eclipse :

  • Le paramétrage de la recherche multi-fichiers est plus complet.
  • Le mécanisme de recherche dans les préférences est fantastique.
  • L’éditeur CSS d’Aptana est opérationnel sur les fichiers LESS CSS. Il râle beaucoup mais l’auto-complétion CSS reste fonctionnelle.

Toujours à l’avantage d’Aptana/Eclipse, des bogues ou défauts de NetBeans :

  • Sous NetBeans, dans la fenêtre « Properties » (équivalent de « Outline »), impossible d’afficher les membres par ordre d’apparition dans le code.
  • J’ai trouvé un cas où l’auto-complétion des membres d’une classe n’est pas accessible dans NetBeans : lorsqu’une instance est déclarée dans un autre fichier et rapatriée en global (je sais que c’est une horreur mais…).
  • Dans la fenêtre « Action Items » de NetBeans, impossible de n’afficher que les erreurs PHP et pas celles JavaScript par exemple. D’une manière générale cette fenêtre est moins utilisable que la combinaison de fenêtres « Tasks » et « Problems » de Aptana/Eclipse.
  • Il manque à la fenêtre « Search Results » de NetBeans une barre de défilement horizontale.

Alors NetBeans, sans regret

En ce qui me concerne, les défauts de NetBeans sont moins handicapants que ceux d’Aptana ou d’Eclipse. Le seul problème important que j’ai sous NetBeans est l’éditeur de CSS inutilisable sur une syntaxe LESS CSS. Il existe un plugin pour la coloration mais aucune solution pour l’auto-complétion des propriétés CSS. À noter : l’équipe de NetBeans plancherait sur l’intégration de la syntaxe SASS ou LESS.

Sur la manière de penser Objets en PHP par rapport à Java

Java vs PHP, la différence qui change tout

En Java, chaque concept, même le plus insignifiant, mérite presque toujours une classe. Le nombre d’objets instanciés a peu d’impact sur les performances. Les programmes Java sont certes souvent un peu longs à démarrer, le temps de charger la machine virtuelle mais aussi de créer et de configurer le labyrinthe d’objets interconnectés qui forme le programme. Mais une fois le programme initialisé, il est réactif et stable. Java est particulièrement adapté aux traitements côté serveur. J’ai connu des démons écrits en Java turbinant un an durant sans un redémarrage et sans dire un mot. Java rejoint par endroit la stabilité des AS/400.

Un programme PHP est relancé à chaque requête HTTP reçue. Il n’est pas, comme en Java, chargé en mémoire et en attente des évènements. Il n’existe aucune manière de conserver un objet en mémoire pour le réutiliser d’une requête HTTP à l’autre. Les programmes PHP sont sans cesse réinterprétés et relancés, parfois plusieurs dizaines de fois par secondes.

Aussi la question de la performance du chargement des programmes PHP est cruciale. Les développeurs du langage PHP ont le souci permanent de la performance. Toutes les nouveautés sont orientées, courbées, pliées dans le sens de la performance, ce qui donne parfois des choses étonnantes comme la manière « file system » de penser les namespaces. Mais les créateurs du langage ne développent pas à notre place et, en définitive, si l’on ne fait pas l’effort de penser à notre tour dans le sens de la performance, la vélocité de l’écosystème PHP sera vaine.

Or l’instanciation des objets prend du temps. Nous devons créer nos objets PHP avec parcimonie…

Le couteau suisse de PHP : les tableaux associatifs

Faudrait-il pour autant revenir à un mode de raisonnement procédural ? Non. À tout le moins, pas au sens des langages procéduraux. Car PHP est malgré tout un langage à Objets.

PHP offre un outil optimisé, les tableaux associatifs, afin d’éviter la POO dans les petits détails. PHP incite à utiliser les tableaux associatifs là où en Java nous créerions des classes garnies de setters et de getters.

Prenons un exemple. Nous souhaitons représenter un point coloré. La manière Java d’écrire cela ressemblera à :

// On crée la classe…
 
public class ColoredPoint {
	private int x, y;
	private String colorCode;
 
	public ColoredPoint(int x, int y, String colorCode) {
		this.x = x;
		this.y = y;
		this.colorCode = colorCode;
	}

	public String getColorCode() {
		return this.colorCode;
	}

	public String getX() {
		return this.x;
	}

	public String getY() {
		return this.y;
	}
}
 
// … puis on l'utilise :
 
ColoredPoint cp = new ColoredPoint(10, 12, "99FF99");

En PHP nous écrirons plutôt :

$cp = array('x' => 10, 'y' => 12, 'color-code' => '99FF99');

Le code Java est intéressant à moyen terme. Le programme est compilé une seule fois, puis chargé également une seule fois, aussi les temps de compilation et de chargement ne comptent pas. Ensuite le programme attend les évènements (requêtes HTTP ou autres) et instancie des objets. N’en doutons pas, au bout de quelques dizaines ou centaines de réponses aux évènements, et quelques milliers d’instanciations plus tard, les appels aux getters se révèleront plus rapides qu’une recherche dans un tableau associatif.

Un programme PHP équivalent n’atteindra pas le millier d’instanciations. Il manipulera les quelques dizaines d’éléments nécessaires au traitement de la requête HTTP et rendra la main au bout de quelques microsecondes. Il sera recompilé et relancé une demi-seconde plus tard et pour un résultat similaire. Pas d’inertie en PHP.

Avec l’inertie, Java gagne. Mais est-ce bien certain ? Tout dépend des traitements. Les API Java mettent en jeu une foule d’objets et sont lentes. La complexe API de calcul d’un SHA1 en Java restera toujours plus lente que la fonction bien optimisée de PHP dédiée à cette tâche. En outre il arrive souvent que le temps des traitements soit insignifiant devant celui des I/O. Au final, en Java, nous avons la possibilité de stocker en RAM des choses prêtes à resservir là où PHP est condamné à toujours réitérer ses efforts sans plus d’organisation, et cela est un atout de Java pour qui sait s’en servir.

Pour revenir à notre code PHP, sa concision joue en faveur d’une compilation et d’un chargement plus rapide. Et la création d’un tableau PHP est plus performante que l’instanciation d’une classe.

Mais, me direz-vous, notre « point coloré » fera forcément l’objet de traitements. Si l’on utilise un tableau, on ne peut pas lui adjoindre de méthodes pour ces traitements.

Exact ! D’où la question qui suit.

En PHP, jusqu’où aller dans la POO ?

Le langage PHP pose la question de jusqu’à quel niveau de précision on reste dans l’orienté objet. Un arbitrage doit être fait : cet objet qu’on hésite à créer, l’utilisera-t-on partout dans le programme ou juste pour un traitement particulier ? A-t-on besoin d’une dizaine de méthodes ou de juste les getters et une fonction de traitement ?

En Java on arbitre presque toujours en faveur d’une classe. On va loin dans les détails insignifiants, on va jusqu’à créer des petites classes privées pour les besoin internes d’une classe. En Java tout ce qui n’est pas un type primitif mérite une classe.

En PHP, au contraire, mieux vaut un tableau qu’un petit objet.

En ce qui me concerne voici une règle que je suis : lorsque j’hésite, j’utilise par défaut un tableau associatif. Dès que le code pour manipuler ce tableau devient plus complexe que s’il s’agissait d’un objet, je recode avec une classe.

Un peu plus sur les tableaux PHP, le principe du copy-on-write

Les tableaux en PHP sont implémentés selon le principe du copy-on-write ou copie sur écriture. Le paramètre n’est copié que si on y accède en écriture. Et c’est pourquoi il serait contreproductif, dans un but d’optimisation, de passer par référence un tableau à une fonction.

Un exemple :

function test(array $a) {
	echo $a[0]; // on utilise la tableau en lecture
	// jusqu'ici le $a original n'est pas dupliqué
	$a[1] = 'haricot'; // duplication du $a original et modification de la copie
}
 
$a = array('ananas', 'banane', 'tomate');
test($a);

Ou bien un autre exemple, plus simple encore :

$a = array('ananas', 'banane', 'tomate');
$b = $a;
// ici $b et $a pointent sur le même tableau.
$b[1] = 'haricot'; // copie sur écriture
// ici $b et $a pointent sur deux tableaux différents.

Les tableaux PHP sont toujours passés par référence, et l’opérateur & sert en fait à désactiver la copie sur écriture. Le copy-on-write rend la manipulation des tableaux PHP similaire à celle des objets constants clonables (à l’instar des String de Java).

PHP est un langage à Objets : créons des objets. PHP fournit des tableaux polyvalents et optimisés : dans les méthodes de nos objets, évitons d’instancier trop de petits objets et utilisons des tableaux.

Les méthodes GET et POST du protocole HTTP

La méthode GET d’un formulaire HTML ou d’un envoi en Ajax n’est pas juste une manière de passer des paramètres dans l’URL. GET est une « méthode » (au sens d’une « fonction » d’un langage de programmation) du protocole HTTP. Par exemple l’URL www.monsite.com/ma-page?lang=fr peut être utilisée par une requête HTTP de type GET ou POST. S’il y a un paramètre, alors en GET il sera ajouté dans l’URL ce qui donnera : www.monsite.com/ma-page?lang=fr&mon-param=ma-valeur. En POST l’URL est utilisée telle qu’elle est et les paramètres sont envoyés à côté.

Le protocole HTTP

La RFC 2616 du W3C définit les méthodes du protocole HTTP, dont notamment les quatre suivantes pleinement exploitées en architecture REST : GET (lecture), POST (tout type d’écriture), PUT (écriture à un endroit donné à la manière d’une valeur dans un tableau associatif) et DELETE (suppression). La syntaxe des formulaires HTML n’autorise que GET et POST et dans cet article nous nous en contenterons également. Toutefois, notons que les quatre méthodes restent utilisables en Ajax (JavaScript) sur les navigateurs modernes.

GET est « safe », c’est-à-dire qu’une requête HTTP GET n’a pas de conséquence significative autre que le chargement d’une ressource. GET est en outre « idempotent » ce qui signifie que plusieurs requêtes HTTP GET identiques lancées à la suite provoquent le même effet (retournent le même contenu Web) qu’une seule. Le navigateur peut donc mettre en cache la réponse à une requête GET. GET est idéale pour les accès en lecture. Et c’est en GET que le navigateur accède au serveur lorsqu’on saisie une URL dans la barre d’adresse.

POST est au contraire non « idempotent » et non « safe » ce qui en fait la méthode la plus généraliste du protocole HTTP. On peut alors en faire ce qu’on veut sans contrevenir à la norme. On l’utilisera pour tous les accès en écriture : les ajouts, modifications et suppressions. Le résultat d’une requête POST n’est pas mis en cache par le navigateur (inutile puisqu’elle n’est pas « idempotent »).

Coté navigateur, bien choisir entre GET et POST

Pour les accès en écriture, la méthode POST doit être utilisée. C’est obligatoire. Celui qui modifie le contenu de son site Web à coups de requêtes GET est en dehors de la norme HTTP et cela a des conséquences. Si par exemple on voulait faire deux ajouts identiques en GET, le navigateur pourrait décider de mettre en cache la réponse et la resservir plutôt que de lancer deux fois l’ajout : absurde.

Pour les accès en lecture, GET doit être préféré.

Coté serveur, bien gérer POST

En PHP, si une ressource Web existe, le langage la rend par défaut accessible à la fois en HTTP GET et en HTTP POST. Ainsi, en réponse à une requête HTTP GET ou POST sans paramètres, une page PHP fournira le même document. Nous devons comprendre que c’est un choix de PHP et non pas une manière générale de faire. Par exemple en Java on reçoit les requêtes HTTP GET et POST dans deux méthodes différentes et on choisit explicitement de faire ou non le même traitement.

Le double accès par défaut des ressources PHP ne pose pas de problème particulier. La plupart des accès se feront de toute manière en GET pour la lecture des pages du site.

En écriture cependant, suite à la réception en POST des données saisies dans un formulaire HTML, un programme PHP ne devrait pas renvoyer un document Web. En effet, ce dernier ne serait pas mis en cache, ce qui pose un problème de performance, et puis le navigateur risquerait de relancer la requête POST si l’utilisateur jouait des boutons « Précédent » et « Suivant ». La RFC du W3C recommande de retourner un statut de réponse HTTP 200 (OK), 204 (Pas de contenu), 201 (Créé) ou 303 (Voir aussi). Les premiers statuts de réponse seront exploitables en Ajax. Le dernier redirigera le navigateur vers une URL à charger en GET.

Dans le cas où l’envoi en POST d’un formulaire HTML créerait ou une nouvelle page Web (cas d’un nouvel article dans un blog) ou modifierait une page existante (cas de l’ajout d’un commentaire sous l’article), le programme PHP ne devrait pas afficher la page directement. Il devrait renvoyer le code 303 accompagné de l’URL de la page à (re)charger.

En PHP, à la suite du traitement réussi des données envoyées, on écrira ceci :

header("Location: the/url/to/load", true, 303);
exit;

Comment transférer plus rapidement un site Web sur un hébergement mutualisé

Sur une connexion béninoise, j’ai réduit mon temps de déploiement d’un site Web de quatre heures à trente minutes.

Trois problèmes, une solution…

Lors de l’upload d’un site Web, les connexions à bas débits posent plusieurs problèmes et le premier est l’intégrité des fichiers. Je prends l’exemple d’un projet à base de WordPress classique : plus de mille trois cents fichiers et dossiers. En les transférant directement par un logiciel client FTP sur une connexion un peu faible, le risque que l’un des fichiers n’arrive pas entier est élevé.

Les problèmes suivants sont la bande passante et le temps de transfert. Transférer des centaines de petits fichiers demande de nombreuses commandes FTP. Les transférer en une seule opération est moins couteux en bande passante et en temps. Le site est en outre composé de nombreux fichiers textuels qui gagneraient à être compressés le temps de l’upload.

Nous allons donc compresser tout le site Web avant de le transférer.

Il nous faudra ensuite le décompresser sur le serveur distant. En hébergement mutualisé nos n’avons pas accès au shell distant via SSH. Notre seul outil est le langage PHP. Utilisons-le.

PHP donne accès au shell du serveur au travers des commandes exec, passthru et system. La dernière affiche la sortie de la commande et donc les éventuels messages d’erreurs, c’est elle que nous utiliserons. Certains hébergeurs proposent aussi un module ZipArchive. Nous avons donc l’embarras du choix.

La procédure à suivre

  1. Compresser le site Web en un seul fichier « deploy.tar.bz2 » ou « deploy.tar.gz ».
  2. Depuis le client FTP (par exemple FileZilla), sur l’hébergement distant, créer un dossier caché .tmp1234 (pour une plus grande sécurité, remplacer « tmp1234 » par un code de votre choix). Puis y transférer le fichier compressé ainsi que le fichier PHP chargé de la décompression. Je donne plus bas les codes PHP pour les différents formats.
  3. Depuis un navigateur, charger la page PHP de décompression. Par exemple : www.votre-site-web.com/.tmp1234/uncompress-tarbz2.php.
  4. Depuis le client FTP, rafraichir l’affichage du contenu du dossier caché. Le site Web décompressé s’y trouve. Le déplacer à la racine ou au bon endroit dans le site via un glisser-déplacer sur le dossier parent ...
  5. Depuis le client FTP toujours, supprimer le dossier caché et son contenu (le fichier compressé et la PHP de décompression).

Codes PHP de décompression

Vous choisirez le fichier PHP qu’il vous faut selon le format de compression.

Décompresser le format .tar.bz2

Le contenu du fichier uncompress-tarbz2.php :

<?php
$res = system('tar -xjf deploy.tar.bz2');
echo $res === false ? 'failed' : 'ok';

Décompresser le format .tar.gz

Le contenu du fichier uncompress-targz.php :

<?php
$res = system('tar -xzf deploy.tar.gz');
echo $res === false ? 'failed' : 'ok';

Décompresser le format .zip par le module PHP

Le contenu du fichier uncompress-zip.php ne fonctionnera pas sur tous les hébergeurs. Il s’appuie sur le module ZipArchive de PHP :

<?php
$zip = new ZipArchive();
$res = $zip->open('deploy.zip');
if ($res === true) {
	$zip->extractTo('./');
	$zip->close();
	echo 'ok';
} else
	echo 'failed';

Décompresser le format .zip par la commande Shell

Si l’utilitaire unzip est installé chez l’hébergeur, on peut tenter de décompresser les fichiers .zip par le shell. Voici le contenu de uncompress-zip-alt.php :

<?php
$res = system('unzip deploy.zip');
echo $res === false ? 'failed' : 'ok';

En positionnement CSS les vieux pixels poussiéreux : poubelle !

Avertissement. Je laisse cet article en ligne pour l’historique mais il utilise une définition erronée de la notion de pixel. Ce que je pensais être les pixels sont en fait des “points physiques” (pixel device) c’est-à-dire PAS les pixels que l’on manipule en CSS. Le pixel en CSS est le 96ème d’un pouce observé à un bras de distance. Les écrans classiques font 96 dpi et donc dessus un pixel CSS équivaut à un point d’écran mais cela n’est plus vrai sur les écrans à haute résolution. Cela signifie qu’on peut faire du design adaptatif en pixels.

Pourquoi ne faut-il plus utiliser les pixels dans les règles CSS pour écrans (le média screen) ?

C’est parce que… la taille du pixel devient trop variable d’un écran à l’autre. La finesse de l’affichage des écrans s’accroit sans cesse. Les résolutions sont de plus en plus hautes même sur des écrans de téléphones de tailles réduites. La très classique résolution de 1024×768 pixels sur des écrans d’ordinateur de quatorze ou quinze pouces sera bientôt rejointe par celle des smartphones qui tiennent dans la poche. Gageons que celle des écrans d’ordinateurs s’envolera à son tour. Avec les écrans Retina Apple a lancé la course à la finesse, et il est bien possible que dans les prochaines années les écrans multiplient plusieurs fois leur nombre de pixels.

Aussi, une largeur en pixels ne permet plus d’avoir une idée de la taille affichée. Par exemple sur les écrans d’ordinateurs actuels une barre latérale large de trois cents pixels est affichée sur six ou sept centimètres et peut contenir une quarantaine de caractères. Sur les prochaines générations d’écrans, les mêmes trois cent pixels pourraient bien ne faire que deux centimètres de largeur et n’afficher que quelques caractères.

Je parle de positionnement en CSS mais il est évident que les tailles de caractères doivent encore moins être définies en pixels, la lisibilité des textes du site en dépend. Cela explique pourquoi le reset CSS de Eric Meyer définit une taille de police par défaut à 100%, c’est-à-dire qu’elle est laissée au choix du navigateur et des préférences de l’utilisateur.

Deux unités sont à privilégier en positionnement CSS : le pourcentage (%) et le cadratin (em).

Relativement à la largeur des blocs : le pourcentage (« % »)

Le pourcentage est l’unité privilégiée par Ethan Marcotte pour faire du responsive Web design, c’est-à-dire du design proportionnel ou encore « fluide ». Un design avec des largeurs proportionnelles est « élastique ». Il s’adapte à la largeur de l’écran, que celui-ci fasse trois ou vingt-trois pouces, et sans se soucier du nombre de pixels.

Relativement à la taille du texte : le cadratin (« em »)

La dimension d’un cadratin (la largeur d’un espace de texte, ou encore de la lettre « M ») est par nature lisible par l’œil humain. Et donc en travaillant en em on indexe le design sur les capacités de l’œil humain. Les blocs positionnés conserveront une largeur cohérente pour l’humain quelle que soit la finesse de la résolution ou la largeur de l’écran. Une barre latérale de 18.75em aura une largeur sensiblement équivalente sur les écrans de tablettes, de smartphones, d’ordinateurs etc. d’aujourd’hui et de demain.

Par rapport à nos habitudes sur les écrans d’ordinateurs classiques, la règle de conversion à suivre est simple : 16 pixels font 1 em.

L’unité em est utilisée pour les hauteurs dans les designs responsive (fluides). C’est également l’unité « à tout faire » des designs non proportionnels et en particulier des grilles frameless. Au passage, en ce qui concerne les grilles des designs, je recommande chaudement au lecteur l’unité em plutôt que les pourcentages.

L’unité em a en outre l’avantage d’être facile à manipuler pour l’impression (le média print). Elle est en effet indexée sur le point (pt). Par exemple si la taille du texte est 12pt alors le cadratin mesure douze points. Une mise en page réalisée pour écran sera donc réutilisable sur imprimante.

Pixels malgré tout ?

Il m’arrive encore d’utiliser les pixels sur écran dans un cas particulier : les images non vectorielles. Ces images ont en effet une taille optimale d’affichage en pixels et il est parfois justifié, pour les règles CSS qui les concernent (les décalages pour les images de background notamment), de travailler en pixels.

Aux armes ! Défendons la sémantique en CSS !

Raphaël Goetter a publié dimanche une charge contre l’usage systématique de la sémantique en CSS. L’argument qui m’intéresse est qu’une classe CSS sémantique ne serait pas réutilisable. On imagine mal en effet comment une classe .sticky-video pourrait servir à positionner un bloc autre que celui des vidéos mises en avant. Mais de quelle réutilisabilité parle-t-on ?

Je prendrai dans cet article deux domaines de l’habillage des pages Web : le titrage et le positionnement.

Le titrage d’abord. L’article de Nicole Sullivan sur les éléments de titre est convainquant. L’auteur suggère d’utiliser des classes réutilisables .h1, .h2, .h3 etc. afin d’habiller les titres. Si un design prévoit cinq types d’habillage des titres, on comprend bien que cela ait du sens de marquer en HTML les éléments de titres par des classes CSS réutilisables, plutôt que d’utiliser en CSS des sélecteurs complexes et nombreux. Et puis ces classes aideront à décliner les titres de manière homogène selon les médias par media queries.

Venons-en au positionnement en CSS.

En positionnement CSS, le raisonnement de Nicole S. ne donnerait pas des classes du type .left ou .span3 comme fournies par les frameworks CSS Knacss et Bootstrap. L’équivalent de telles classes en titrage ressemblerait plutôt à .titre-encadré-bleu à la place de .h2. Pour positionner à la manière des titrages de Nicole S., il faudrait plutôt utiliser des classes génériques telles que .pos-type-1, .pos-type-2 etc. Ainsi si le designer définissait des types de positionnement et s’y tenait, cela aiderait certainement à les décliner de manière homogène selon les médias. Cela dit par expérience le design ne se prête pas facilement à une homogénéisation du positionnement des blocs.

Pour résumer, il me semble que la pratique des classes CSS réutilisables se justifie dès que l’on peut définir des types homogènes (de titrage, de positionnement etc.). L’apparence est alors déclinable selon les médias. Mais en aucun cas le nommage de ces classes CSS ne devrait dépendre de l’une de ces déclinaisons !

Et donc en dehors des types homogènes, un nommage sémantique reste à mon avis une bonne pratique. Car enfin à quoi sert la sémantique ? La sémantique en CSS ne sert-elle pas précisément à rendre le code CSS plus facile à maintenir et à décliner sur différents médias ?

En vérité ce sont les classes « techniques » de Knacss et Bootstrap qui ne sont pas réutilisables. Si par exemple le nom d’une classe implique une mise en page sur trois colonnes pour des écrans de quinze pouces, comment passer à sept colonnes sur les écrans plus larges ?

Certes, le langage CSS est de bas niveau et force effectivement à la répétition et au copier-coller. Les préprocesseurs CSS (dont LESS) répondent élégamment au problème de la réutilisation sans pour autant s’assoir sur la sémantique.

Un bémol toutefois, quoique très spécifique. Il me semble que des classes « techniques » en CSS se justifieraient dans le cas d’une affectation en dynamique sur des éléments HTML, en JavaScript. On peut en effet gérer l’apparence dynamiquement par JavaScript, selon la largeur du navigateur, comme le fait Facebook.

Web sémantique : RDFa Lite joue et gagne

Le Web sémantique. Derrière ce nom se cache l’idée d’ajouter du sens (de la sémantique) sur des éléments HTML. Je tente ici un récapitulatif des évolutions dans le domaine.

Deux standards sont en concurrence depuis des années : RDFa et les microdata (ces dernières héritent des microformats conçus pour HTML4).

Depuis quelques années on pouvait lire que RDFa était le futur standard, préféré par le W3C. Mais il était complexe et alourdissait considérablement les pages Web. Aussi Google avait-il opté pour une implémentation des microformats. Les microformats sont un détournement des classes CSS : des mot-clés spécifiés par les microformats sont utilisés comme marqueurs parmi les classes CSS. Le principal inconvénient de cette technique est qu’elle n’est pas propre : deux normes se mélangent car il est tentant de styler (en CSS) des marqueurs microformats. En 2011 avec la sortie de HTML5 et des nouveaux attributs itemXXX valables sur tous les éléments HTML, le principal inconvénient de ce standard était balayé : les microformats devenus microdata devenaient plus crédibles. Pour en savoir plus sur les microdata et les microformats, je suggère ce tutoriel.

Un juin 2011 Google, Bing et Yahoo! s’étaient unis pour sortir schema.org, un catalogue de schémas pour microdata. Et ce catalogue s’est, depuis, enrichi avec constance de schémas touchant de nombreux domaines.

Un an plus tard, en juin 2012, le W3C fait de RDFa un standard officiel. Un sous-ensemble simplifié de la nouvelle norme est publié également : RDFa Lite dont la spécification est ici (en anglais). RDFa Lite est destiné à remplacer les microdata, et de fait il est d’une simplicité comparable aux microdata. On peut utiliser avec RDFa Lite le catalogue schema.org. Entre temps Google a commencé à implémenter RDFa : au final, c’est RDFa qui a gagné. Pour en savoir plus sur pourquoi et comment passer des microdata à RDFa Lite, lire l’article de Manu Sporny (en anglais).

Cette histoire a une conséquence. Jusqu’à juin dernier l’indécision entre deux standards poussait la plupart des acteurs du Web à attendre. Le Web sémantique n’était pas mature. Aujourd’hui le problème est tranché. Le Web sémantique, c’est faire porter du sens à des éléments HTML afin de les rendre utilisables par des robots. Et les premiers robots du Web sont ceux des moteurs de recherche. À l’avenir le référencement des sites Web qui n’implémenteront pas RDFa Lite sera désavantagé.

Des grilles et des CSS : comment travailler vite et sans frameworks

Ce tutoriel traite de l’implémentation des grilles frameless (non fluides). Le lecteur y trouvera comment se créer ses propres outils de positionnement sur la grille directement en CSS ou bien en LESS CSS, au choix.

Le problème : CSS fait perdre du temps

Le langage CSS est de bas niveau. Il oblige l’intégrateur à de nombreuses répétitions qui, en plus d’être longues à saisir, seront autant de boulets lors de la maintenance.

Les frameworks CSS sont à mon avis engagés dans une mauvaise direction, celle d’une entorse à la séparation du fond et de la forme. Mieux vaudrait des « frameworks LESS ». Mais il est également facile de se faire soi-même les outils nécessaires à l’usage d’une grille.

Ceux qui codent directement en CSS sont condamnés à un copier-coller massif, je fournirai du moins les valeurs prêtes à coller.

Le préprocesseur LESS CSS ajoute au langage CSS des fonctionnalités qui nous évitent les répétitions. Notez que j’utilise LESS et donc j’écris sur LESS, mais je n’ai rien contre SASS. Pour utiliser LESS CSS simplement, pensez à Less Now.

Des variables pour les colonnes et les lignes de la grille

Il nous faut des variables pour les largeurs de colonnes et les hauteurs de lignes. En CSS on « simule » les variables au moyen de marqueurs laissés en commentaires, en LESS on utilise simplement les variables.

D’abord un dessin :

Grille et variables

Ensuite l’explication. Je suggère les conventions de nommage suivantes :

  • Les largeurs de colonnes sont suffixées par « c » : 1c, 2c, 3c, etc.
  • La largeur d’une gouttière est représentée par g.
  • Les largeurs de colonnes plus une gouttière sont suffixées par « cg » : 1cg, 2cg, 3cg, etc.
  • Les hauteurs des lignes sont suffixées par « r » : 1r, 2r, 3r, etc.

Voyons un exemple. Nous souhaitons créer un bloc large de deux colonnes et haut d’une ligne. Et nous voudrions en outre qu’il recouvre les colonnes numéro 2 et 3 (il est donc décalé à droite d’une colonne et une gouttière). En CSS cela donne :

.my-block {
	height: 1.25em; /* 1r */
	margin-left: 3.75em; /* 1cg */
	width: 6.25em; /* 2c */
}

En LESS CSS on écrira :

.my-block {
	height: @1r;
	margin-left: @1cg;
	width: @2c;
}

Facile, non ? Il reste maintenant à générer les variables.

Générer les variables CSS ou LESS à l’aide d’un tableur

Paramétrage

Paramétrage

J’utilise Gnumeric car il est aussi léger qu’une calculatrice mais n’importe quel tableur fera l’affaire. Il vous faudra toutefois le configurer afin qu’il utilise le point comme séparateur des décimales.

La feuille de calculs comporte trois parties : un bloc de paramétrage, le bloc des colonnes sans et avec gouttières, et celui des lignes. Faites correspondre à votre grille les trois paramètres dans les cellules colorées.

Les colonnes sans et avec gouttières

Les colonnes sans et avec gouttières

Les lignes

Les lignes

Les colonnes « CSS » fournissent la valeur en em ainsi que le marqueur en commentaire pour rappeler de quelle variable il s’agit. Ceux qui travaillent en CSS feront donc des aller-retours durant tout leur travail entre la feuille de calculs et leur éditeur de CSS.

Les utilisateurs de LESS CSS se contenteront de copier le contenu des trois colonnes « LESS » au début de leur fichier LESS et ils utiliseront ensuite les variables normalement.

Téléchargez le fichier tableur : Calculs pour grilles Frameless (au format Gnumeric, ODF et Excel).

Vous voilà en selle.

Note à propos de l’unité « em »…

En attendant l’implémentation par les navigateurs de l’unité rem, nous devons utiliser em pour notre positionnement en CSS. Or em est une valeur contextuelle, elle dépend de font-size qui est une propriété héritée. Un travail propre demandera donc deux préalables :

  1. utiliser un « reset CSS » comme celui d’Éric Meyer afin d’attribuer à tous les éléments HTML la même valeur de font-size, celle par défaut du navigateur ;
  2. n’utiliser font-size que dans les éléments en bout de hiérarchie : par exemple sur .my-content-block p plutôt que .my-content-block.

LESS CSS sans préprocessing sur le serveur ni sur le navigateur ? Less Now !

Vous connaissez surement LESS CSS de nom. Et vous aussi, tout comme moi durant des années, vous vous dites : « il est vrai que CSS est un peu rustre mais les autres solutions ne sont pas standards, il serait imprudent de bosser avec ». Et comme vous vous doutez bien que l’essayer, c’est l’adopter, puisque les critiques sont toutes positives, alors le plus simple est encore de ne pas l’essayer.

Cela dit ces considérations ne vous empêchent pas de vous tenir au courant et vous voilà en train de lire cet article.

Et vous êtes chanceux car j’ai essayé pour vous.

Ce que LESS apporte aux CSS

LESS permet d’écrire du code CSS sans répétitions.

Par exemple dans les sélecteurs :

En CSS En LESS CSS
.my-block p,
.my-block li {
  text-align: justify;
}
.my-block {
  p,
  li {
    text-align: justify;
  }
}

Pas de répétition dans les valeurs de propriétés :

En CSS En LESS CSS
.my-title {
  color : #cde; /* title color */
}
.other-element {
  color : #cde; /* title color */
}
@title-color: #cde;
.my-title {
  color : @title-color;
}
.other-element {
  color : @title-color;
}

Pas de répétition des groupes de propriétés :

En CSS En LESS CSS
pre {
  text-wrap: wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
}
.other-block {
  text-wrap: wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
}
.wrap() {
  text-wrap: wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
}
pre {
  .wrap;
}
.other-block {
  .wrap;
}

LESS CSS fournit aussi des fonctions de calcul et de manipulation des couleurs (lighten pour éclaircir, darken pour assombrir etc.) dont le but est là-encore de factoriser le code.

Le lecteur trouvera l’ensemble de la syntaxe sur le site de LESS CSS.

Déployer… ou pas

Le préprocesseur LESS CSS est écrit en JavaScript. Il compile du code LESS en CSS. Il peut également « minifier » le code CSS qu’il génère, et depuis que Google s’intéresse à la performance des sites c’est toujours ça de gagné.

Le site officiel de LESS CSS recommande deux méthodes pour utiliser LESS CSS : un préprocessing du côté client sur le navigateur de l’internaute, ou bien du côté du serveur Web. Eh bien aucune de ces deux méthodes n’est intéressante.

Les défauts d’une compilation LESS CSS sur le navigateur :

  1. Un préprocessing sur le navigateur alourdit le chargement et surtout l’affichage de la page Web.
  2. Lorsque le JavaScript est désactivé sur le navigateur, la page n’est plus du tout stylée.
  3. Les robots des moteurs de recherches utilisent le code CSS pour évaluer quel contenu est mis en avant. Toutefois ils ne peuvent probablement pas interpréter le code LESS et les pages Web ne sont donc pas scannées normalement.
  4. Publier un site Web reposant sur une technologie non standard pose un problème de pérennité.

Et du côté du serveur :

  1. L’exécution du compilateur JavaScript demande des installations spécifiques inaccessibles sur les hébergements mutualisés. Notons qu’il existe une implémentation en PHP mais qui représente aussi un risque de s’écarter de la syntaxe LESS, laquelle n’est déjà pas un standard.
  2. Et, de même que pour un préprocessing sur le navigateur, publier un site Web reposant sur une technologie non standard pose un problème de pérennité.

Mais il existe une troisième voie.

Préprocesser sur l’ordinateur de l’intégrateur

Une solution plus élégante est de compiler le code LESS en CSS directement sur l’ordinateur du webmestre. Ainsi c’est la CSS générée qui est déployée et incluse dans le code HTML.

Plusieurs utilitaires font ce travail de compilation : LESS.app est probablement la meilleure référence mais il tourne sur Mac OS uniquement. SimpLESS est orienté Windows, il plaira aux adeptes de la configuration visuelle. Quant à moi je vous suggère Less Now qui fonctionnera à l’identique sur Linux et tous les systèmes d’exploitation disposant d’une machine virtuelle Java. Less Now, on le configure et on l’oublie.

Voici la marche à suivre :

  1. Télécharger Less Now. Installer également une machine virtuelle Java si ce n’est déjà fait.
  2. Créer un fichier de configuration en prenant exemple sur celui proposé, et mentionner les dossiers qui contiennent des fichiers « .less ».
  3. Lancer Less Now et le laisser tourner.
  4. Sans plus de préoccupation, retourner à l’environnement de développement habituel.

Less Now détecte en temps réel toute modification aux fichiers LESS et régénère le cas échéant le fichier CSS correspondant.

Notons que Less Now embarque le préprocesseur LESS CSS officiel qu’il exécute via Rhino, l’interpréteur JavaScript de Mozilla. La syntaxe LESS CSS est donc la bonne.

Qu’est-ce qu’un « responsive Web design » : la vraie définition, celle d’Ethan Marcotte

Suite aux réactions déplacées d’un lecteur de mon article sur pourquoi les grilles « responsive » sont une mode qui passera, je me suis aperçu que le Web francophone regorge de définitions erronées ou ambigües. Qu’est-ce qu’un design « responsive » ?

Le mot « responsive » a été introduit par le Web designer Ethan Marcotte. Ethan a écrit un livre qui est en passe de devenir un monument : « Responsive Web Design ». Il en existe une version traduite en français chez les éditions Eyrolles. Je recommande chaudement la lecture de ce livre. Il est court (139 pages) et facile à lire. Au fil des pages, avec passion et humour, l’air de rien, l’auteur change (en mieux !) notre manière de voir le design Web.

Je cite le passage du livre qui nous intéresse. Voici ce qu’est un design « responsive » :

  1. Une grille de mise en page flexible,
  2. Des images et des médias flexibles,
  3. Les media queries, un module de spécification CSS 3.

« Flexible », cela veut dire « fluide » ou encore « proportionnel ».

Donc le « responsive » c’est du fluide à la sauce CSS 3.

Fluide, cela signifie que la page Web se compresse ou s’élargit selon la largeur de la fenêtre du navigateur. Rien de bien nouveau sous le soleil, en CSS 2 on pouvait déjà le faire et ce blog en est un exemple (modifiez la largeur de votre navigateur pour visualiser l’adaptation). Cependant la taille des caractères des textes ne peut pas suivre le mouvement de rétrécissement ou d’élargissement, et il y avait donc en CSS 2 une limite à l’élasticité. On définissait alors une fourchette de largeurs dans laquelle l’affichage pouvait être rendu décemment.

Les media queries de CSS 3 apportent la possibilité de définir plusieurs fourchettes. Et donc faire du « responsive », c’est faire du fluide à l’ancienne mais « plusieurs fois », dans plusieurs fourchettes différentes de largeurs. Le site d’Ethan Marcotte donné plus haut, ou encore la partie principale de ce site, sont des exemples de design « responsive ».

Donc « responsive » n’est pas synonyme de : « adapté une multitude d’écrans de mobiles, de tablettes et d’ordinateurs ». « Responsive » c’est adapté à tous ces écrans et fluide.

Voilà. Tout est dit.

Le fluide (« responsive ») n’est pas la seule manière de faire du design adapté à plusieurs largeurs d’écrans. Il reste possible de faire du design non fluide et de l’adapter, toujours grâce aux media queries, à plusieurs largeurs d’écrans. On parle alors de design moderne (à base de CSS 3), mais on ne peut plus parler de design « responsive ». Un exemple : les grilles frameless.

Maintenant que vous, lecteur, avez compris de quoi il retourne, je vous suggère de lire ma critique donnée en premier lien là-haut : pourquoi les grilles « responsive » et les frameworks CSS sont une mode qui passera.

Pourquoi préciser le média « screen » dans les media queries ?

Les tutoriels sur les « medias queries » suggèrent souvent une syntaxe comme celle-ci :

@media screen and (max-width: 1000px) {
}

Mais pourquoi faudrait-il préciser le média “screen” dans les media queries ? C’est une vraie question car je n’ai lu aucune justification.

Pour mes sites, j’ai pris le parti de ne pas le mettre car le média d’impression (“print”) a besoin des mêmes ajustements dépendants de la largeur de la zone d’impression.

Mais plus généralement, si une feuille de styles est incluse dans le HTML pour tous les types de médias (media="all"), il semblerait cohérent que les ajustements selon les largeurs de médias s’appliquent également à tous les médias.

Toutefois un changement d’unité de mesure s’impose car la notion de pixel (px) est fortement dépendante du média écran. On utilisera plutôt le cadratin (em) afin de travailler relativement à la taille des caractères de texte. Pour convertir les pixels de nos écrans habituels en em, il faut diviser par 16.

La média query ressemble alors à cela :

@media (max-width: 62.5em) {
}

Et cet usage est à mon avis à recommander pour les feuilles de styles qui s’appliquent à tous les médias.

Pourquoi les grilles « responsive » et les frameworks CSS sont une mode qui passera

Je pense sincèrement que le « tout fluide » ne devrait pas être généralisé comme une bonne pratique. Les grilles fluides des designs « responsive » sont inadaptables. Les frameworks Bootstrap, Knacss et consorts de même.

Les grilles fluides sont inadaptables

Prenons l’exemple d’une grille de douze colonnes servant à la conception d’un design de 960 pixels de large. En responsive Web design, le nombre de colonnes de la grille reste invariable sur tout type d’écrans. Sur les terminaux mobiles les plus étroits comme sur les moniteurs extra-larges dernier cri, on travaillera donc toujours sur les mêmes douze colonnes. Bien. Ça a l’avantage de la simplicité.

Sur un écran d’ordinateur de taille moyenne, la grille contient donc douze colonnes de soixante pixels plus les gouttières. Ces soixante pixels seront affichés sur environ deux centimètres : de la place pour quelques caractères d’une taille raisonnablement lisible pour un œil humain.

Prenons maintenant le cas d’un téléphone étroit à l’ancienne. L’affichage est rendu sur une largeur de 128 pixels mais laissons de côté les pixels. L’écran mesure trois centimètres : de la place pour environ quatorze petits caractères par ligne. Les colonnes de notre grille sont maintenant compressées jusqu’à 1,9 millimètre de large. Selon vous, cher lecteur, à quoi sert une grille avec des colonnes de 1,9 millimètre de large ? Selon moi : à rien.

Et les concepteurs des frameworks Bootstrap et Knacss en conviennent également puisque en deçà d’une certaine largeur ils proposent carrément de désactiver les colonnes par media query. Regardez cet exemple pour Bootstrap et cet autre pour Knacss, chargez les pages puis réduisez la largeur de votre navigateur.

Donc une grille fluide prévue pour un écran de quinze pouces ne s’adapte pas aux écrans étroits.

Essayons alors les grands écrans et prenons un magnifique moniteur extra-large de vingt-sept pouces : soixante centimètres de large ! Notre grille s’étire cette fois-ci comme un élastique pour faire des colonnes de… 3,75 centimètres. Comment pourrait-on travailler finement sur des colonnes plus larges qu’un téléphone ?

En résumé, une grille fluide conçue sur un écran de quinze pouces ne permet de faire du bon design que sur des écrans de quinze pouces. Bonjour la fluidité !

Alors à quoi sert une grille fluide ? La grille fluide sert à conserver la même apparence quelle que soit la résolution, c’est-à-dire le degré de finesse des pixels (dpi). Par exemple si les écrans quinze pouces dans deux ans proposent des résolutions triples de celles d’aujourd’hui, les grilles fluides s’afficheront toujours correctement.

Les grilles « frameless » sont la solution

D’abord une démonstration : ouvrez le site des grilles Frameless. Faites varier la largeur de votre navigateur. Pour visualiser la configuration la plus large et celle la plus étroite, utilisez Firefox ou Opera (pas Chrome) puis dézoomez et zoomez.

« Frameless », c’est juste une idée. C’est l’idée que l’œil humain ne change pas fondamentalement de perception de ce qui est large ou fin selon qu’il regarde un écran large ou un écran fin. La largeur d’une colonne de contenu doit être en adéquation avec notre œil et non avec le terminal. Et donc on ne doit pas rendre les blocs de nos pages Web proportionnels à la largeur du terminal (%) mais les garder dans une proportion relative à la taille par défaut des caractères (em).

Pourquoi le caractère ? Parce qu’il reste nécessairement dans une fourchette qui fait sens pour l’œil humain. Et parce qu’il est malgré tout plus souple que les unités « réelles » comme les centimètres.

La taille par défaut d’un caractère est le bon indicateur du degré de finesse ou de grosseur que le constructeur du terminal a voulu donner à l’affichage sur son écran. Il représente toujours l’unité de ce qui est lisible pour l’œil humain. C’est sur lui qu’il faut tout construire.

J’ai ensuite une critique à l’endroit des « frameworks CSS » Bootstrap et Knacss.

Les frameworks CSS Bootstrap et Knacss confondent fond et forme

Les frameworks CSS Bootstrap et Knacss fournissent des classes CSS servant à construire rapidement une mise en page préfabriquée. Ainsi il suffit d’adjoindre une classe « span2 » (en syntaxe Bootstrap) à un élément pour que ce dernier prenne une largeur de deux colonnes de la grille. Lire à ce sujet un tutoriel pour Bootstrap et celui de Knacss.

Personnellement je vois un réel problème à utiliser des informations de type habillage dans le contenu. C’est une entorse à la séparation du fond et de la forme. Cela se paie forcément. Je prends l’exemple d’un élément « article » dont le design est conçu sur un ordinateur doté d’un écran de taille moyenne et qui fait huit colonnes de large :

<article class="span8">…</article>

Imaginons un rendu théorique avec grille et sur mobile. Les frameworks CSS sont « responsive » et donc les huit colonnes rentrent dans l’écran du téléphone. Une colonne seule devient certes inutilisable mais avec huit colonnes ce sera peut-être encore lisible. Sauf que, manque de chance, le designer crée une déclinaison aménagée du design pour mobile et demande à passer l’article sur dix colonnes. Alors que fait-on ? Faudrait-il publier un code HTML différent pour la version mobile ?

Ou bien un exemple plus trivial encore : notre designer change d’avis et nous demande de passer l’article sur neuf colonnes. Voilà une modification de pure forme qui demande de changer le contenu.

Enfin bref je ne vais pas faire le topo sur la séparation du fond et de la forme. Vous lecteur qui me lisez vous savez tout cela, c’est le fondement du métier. Mais pourquoi a-t-il suffit des quelques mots à la mode « responsive » et « framework » pour vous le faire oublier ?

Les « mixins » de LESS CSS sont une solution

Le travail de synthèse réalisé par les concepteurs des frameworks CSS est toutefois excellent. Les classes CSS qu’ils fournissent devraient être non pas des classes mais des groupes de propriétés réutilisables dans les règles CSS. CSS ne permet pas la réutilisation de telles choses, mais LESS le peut et les appelle « mixins ».

LESS CSS est un préprocesseur pour CSS écrit en JavaScript.

Jusqu’à il y a quelques jours j’avais des griefs à l’encontre de cette technologie. Ainsi on peut l’utiliser directement dans les pages Web et laisser le navigateur préprocesser, mais :

  1. C’est forcément lourd côté navigateur d’interpréter la syntaxe LESS via du code JavaScript. Et puis il faut mettre la ressource JavaScript dans l’élément HTML « head » pour forcer son exécution avant l’affichage de la page, ce qui est un défaut en performance.
  2. Si on désactive le JavaScript sur le navigateur, la page n’est plus du tout stylée.
  3. Les robots des moteurs de recherches n’interprètent surement pas les fichiers LESS, ils ne peuvent donc pas scanner le site normalement. Il est en effet très probable que Googlebot utilise les CSS pour affiner son évaluation de quels contenus sont essentiels dans une page Web.
  4. LESS n’est pas un standard. Publier (ou archiver) un site basé là-dessus, c’est s’exposer à des soucis de pérennité.

Il existe une solution pour exécuter LESS CSS côté serveur et servir au navigateur des ressources CSS, mais elle est complexe à déployer et peut-être même infaisable sur des hébergements mutualisés modestes. De plus, le quatrième grief est valable aussi pour du préprocessing côté serveur.

Et donc j’en restais là jusqu’à ce qu’un ami me recommande une solution tournant sur son Mac OS : LESS.app. Le principe est de compiler les fichiers LESS en CSS directement sur la machine du développeur Web. Ensuite sur le site la CSS résultat est incluse normalement et le site fonctionne donc sans préprocesseur. Je me suis mis à la recherche d’une solution équivalente pour Linux et j’ai trouvé Lé-css sorti en open-source par Lukas Dietrich le mois dernier. L’outil n’était pas utilisable dans mon cas et j’ai dû le modifier pour y ajouter un fichier de configuration ainsi que la capacité de travailler sur plusieurs projets en même temps.

Le résultat est Less Now. C’est du java, ça tourne sur tous les systèmes d’exploitation.

Dans le travail de création d’un site Web, Less Now ne représente pas une opération supplémentaire. En effet, depuis que Google parle de performance il est devenu normal de mettre en production un fichier CSS minifié donc différent du source original. Là nous avons un outil qui fait juste « un peu plus » que minifier.

PS. Je sais, ce blog n’applique aucun des conseils que je donne. Les CSS sont faites à la main, c’est du Web 2.0 à l’ancienne, et la partie principale du site est « responsive ». Cependant j’ai eu une révélation il y a quelques jours et j’ai voulu la partager.

Les forums du W229C

Avec deux webmestres béninois nous avons ouvert en juillet les forums du W229C (Web 229 Club). Nous souhaitons en faire une plateforme d’échanges entre professionnels du Web au Bénin.

Les thèmes des discussions sont larges : CSS 3, JavaScript, PHP, CMS, le Web sémantique avec RDFa Lite, le design à grille… La plateforme sert aussi à se connaitre IRL.

Intégrateurs Web, Designeurs Web & Infographistes, Journalistes & Rédacteurs Web & Webmestres du Bénin ? Ou de la sous-région ? Ou bien d’ailleurs ? Rejoignez-nous.

HTML 5 et CSS 3 sur Internet Explorer 6, 7, 8

Internet Explorer est le deuxième navigateur le plus utilisé derrière Chrome. Or les utilisateurs de Windows XP ne disposent au mieux que de IE8, la version 9 ne s’installant que sous Vista et supérieurs. IE6 et IE7 sont en voie d’extinction mais il en subsiste encore, notamment parce qu’ils sont les navigateurs installés par défaut sur XP et Vista.

En résumé il importe d’obtenir un affichage décent sous IE8, et idéalement il faudrait rester à peu près lisible sur IE7 et IE6.

Nouveaux éléments HTML 5

Une règle CSS est nécessaire pour tous les navigateurs qui ne comprennent pas HTML5 :

article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section {
	display:block;
}

Les anciennes versions de IE demandent une chose en plus : inclure le script JavaScript html5shiv. Nous le ferons ci-dessous au moyen d’un commentaire conditionnel.

Les commentaires conditionnels

Microsoft a annoncé que IE 10 ne comprendra pas les commentaires conditionnels. Ils sont cependant opérationnels sur les versions d’Internet Explorer 6, 7 et 8 que nous ciblons. Je recommande éventuellement le tutoriel d’Alsacreations sur comment utiliser les commentaires conditionnels.

JavaScript plutôt que la méthode de Paul Irish

Parmi les bonnes pratiques périmées, mieux vaut abandonner la manière dont Paul Irish suggérait d’employer les commentaires conditionnels en 2008. Sa technique permettait de marquer l’élément html avec des classes CSS ciblant IE (un exemple ici). Mais sur ces anciens navigateurs, les éléments HTML 5 demandent de toute manière l’exécution d’un patch en JavaScript. Aussi, plutôt que de polluer le code HTML, autant le faire en JavaScript.

J’utilise pour ma part le code jQuery suivant :

jQuery.noConflict();
jQuery(document).ready(function() {
	if (jQuery.browser.msie) {
		if (jQuery.browser.version == 6)
			jQuery("html").addClass("ie6 ie67 ie678");
		if (jQuery.browser.version == 7)
			jQuery("html").addClass("ie7 ie67 ie678");
		if (jQuery.browser.version == 8 )
			jQuery("html").addClass("ie8 ie678");
	}
});

Ce code est à placer dans une ressource JavaScript nommée chez moi ie678-patch.js. À l’instar de html5shiv, on inclut cette dernière dans le code HTML via un commentaire conditionnel.

Le commentaire conditionnel pour IE 6, 7 et 8

Ce commentaire est à inclure dans l’élément HTML head :

<!--[if lte IE 8]>
<script src="html5shiv.js"></script>
<script src="jquery.js"></script>
<script src="ie678-patch.js"></script>
<link rel="stylesheet" type="text/css" media="all" href="ie678-patch.css" />
<![endif]-->

NB. En fait pour ma part j’ai intégré le contenu de html5shiv.js dans ie678-patch.js. J’utilise jQuery en version 1.3.2, suffisant et moins volumineux pour notre patch. Puisque j’inclus également une version à jour de la bibliothèque jQuery en fin de code HTML pour le reste des besoins du site, cela signifie que les vieux IE exécutent (sans problème notable) deux versions de jQuery.

CSS 3 sur IE 6, 7 et 8

Une règle à suivre : ne pas polluer son code CSS avec des patchs spécifiques aux vieux navigateurs. Je suggère de dupliquer les règles CSS concernées dans un fichier CSS dédié (nommé chez moi ie678-patch.css et inclus via un commentaire conditionnel) afin d’y ajouter ces patchs.

CSS3 PIE est un patch JavaScript à inclure à l’intérieur même des règles CSS. Il fait fonctionner les styles border-radius, box-shadow, linear-gradient, les background multiples et border-image. Une bonne notice d’utilisation se trouve sur Alsacreations. Je n’ai pas noté de dégradation notable des performances d’affichage avec CSS3 PIE.

Notons que CSS3 PIE est aussi utile sur IE9 pour border-image et linear-gradient.

CSS 3 media queries sur IE 6, 7 et 8

Il existe des patchs JavaScript qui font comprendre les media queries aux anciens IE. Mais ils rendent l’affichage de la page trop lent. Aussi je n’en utilise aucun, je me contente de recopier dans « ie678-patch.css » les règles CSS contenues dans les média queries afin d’obtenir les affichages suivants :

  • Pour IE6 et IE7, viser un affichage pour écran en 800×600.
  • Pour IE8, viser un affichage pour écran en 1024×768.

En effet, IE 6 et 7 tournent le plus souvent sur de vieilles machines mal configurées avec de vieux écrans pourris.

IE8 est un peu plus moderne alors dédions-lui la très classique résolution des écrans moyens.

Positionnement en CSS 2.1 sur IE 6 et 7

Toujours dans le fichier « ie678-patch.css », le positionnement en CSS par inline-block et par layouts de tables sont à corriger ainsi pour IE 6 et 7 :

/* IE6, IE7 - display: inline-block */

.ie67 .my-inline-block-element {
	display: inline;
	zoom: 1;
}

/* IE6, IE7 - display: table */

.ie67 .my-table-or-row-element {
	display: block;
}

.ie67 .my-cell-element {
	display: inline;
	zoom: 1;
}

Notons que nous utilisons ici le marqueur CSS .ie67 ajouté plus haut par notre patch JavaScript « ie678-patch.js ».

Tester sur IE 6, 7 et 8

Pour tester un site sur les anciennes versions de IE, les “compatibility mode” de IE sont à éviter. La seule manière vraiment fiable de tester est d’utiliser une machine virtuelle pour chaque version de IE. Les curieux liront ici la source de cette affirmation.

J’utilise pour ma part une seule machine virtuelle avec Windows XP et IE Collection. IE Collection installe plusieurs versions standalone de Internet Explorer. Ça n’est pas très stable et c’est, en outre, imparfait, car les différents IE partagent nécessairement certaines DLL. Malgré tout, avoir les trois sur une seule VM fait gagner du temps et sur des projets modestes cela est largement suffisant.

Refonte en HTML5

La partie principale de ce site (mais pas le blog ni les contributions open-sources) est passée en HTML5. Les pages sont optimisées pour la navigation sur mobile.

Le portfolio fait l’objet d’une rubrique à part. L’offre reste en page d’accueil.

Art-Décor au Bénin : des bâtiments originaux construits avec des matériaux locaux

Le site de l’entreprise de BTP Art-Décor est sorti cette semaine. Un beau site fait avec les photographies des magnifiques bâtiments construits par Art-Décor. Visitez-le !