Standards Web 13 min de lecture

De zéro à EPUB : assembler un paquet OEB (OEBPS) depuis un projet HTML

#css#epub 3#epubcheck#html#nodejs#oeb#oebps#opf#packaging#zip

EPUB 3 & OEBPS: créez pas à pas un paquet OEBPS (OPF, manifest, spine, nav) et emballez un mini-site HTML/CSS en .epub standard.

De zéro à EPUB : assembler un paquet OEB (OEBPS) depuis un projet HTML

Avant de sortir un livre numérique avec un gros outil, il est très instructif de construire un EPUB 3 à la main. En quelques minutes, vous pouvez empaqueter un mini-site HTML/CSS en un fichier .epub propre, lisible par la plupart des lecteurs, et surtout comprendre ce qu’il y a réellement dans OEBPS, l’OPF, le manifest, le spine et la navigation.

Objectif

L’objectif est de fabriquer pas à pas un EPUB 3 minimal et valide en manipulant directement ses composants: un fichier OPF avec ses métadonnées, un manifest, un spine et un document de navigation. On part d’un contenu HTML/CSS existant, on ajoute une image de couverture et on emballe le tout dans une archive ZIP conforme. Ce tutoriel privilégie la compréhension du cœur OEB plutôt que l’usage d’un éditeur WYSIWYG; en fin de parcours vous obtiendrez un fichier mon.epub simple mais correct contenant une page de chapitre, une table des matières, une feuille de style et une couverture. Comptez une dizaine de minutes si vous tapez les commandes au fil de l’eau.

Objectif et périmètre (OEB/OEBPS en pratique)

Historiquement, OEB signifie Open eBook. Dans EPUB 3, cette notion se concrétise par un dossier OEBPS qui rassemble les éléments essentiels du package: le fichier OPF (package), le manifest qui liste les ressources, le spine qui ordonne la lecture et la navigation (nav.xhtml). Dans ce guide, on se limite volontairement à ces éléments indispensables pour produire un EPUB 3 lisible sans artifices. Le but est double: transformer un contenu HTML/CSS en livre numérique standard et maîtriser la structure exacte du packaging OEB. Le résultat attendu est un fichier mon.epub, avec des métadonnées minimales, un document de navigation, un chapitre unique, une feuille de style et une image de couverture. Pour rester efficace, nous resterons sur un seul chapitre et une table des matières très simple.

Préparer l’arborescence

Commencez par créer l’arborescence canonique d’un EPUB: un fichier mimetype à la racine, un dossier META-INF contenant container.xml, et un dossier OEBPS pour l’OPF, la nav, les contenus, les styles et les médias. Utilisez des noms en minuscules et évitez les espaces; de nombreux lecteurs sont sensibles à la casse et aux chemins.

Exemple en bash pour initialiser le projet:

mkdir -p mon-epub/{META-INF,OEBPS}
cd mon-epub

À la fin de ce tutoriel, vous aurez les éléments suivants au bon endroit: un fichier mimetype à la racine, un fichier META-INF/container.xml qui pointe vers OEBPS/content.opf, et dans OEBPS les fichiers content.opf, nav.xhtml, index.xhtml, style.css, ainsi qu’une image de couverture cover.jpg (ou une variante en PNG).

Fichiers obligatoires: mimetype et container.xml

Un EPUB est une archive ZIP avec une contrainte fondamentale: le fichier mimetype doit être le premier élément de l’archive et il doit être stocké sans compression. Créez dès maintenant ce fichier texte à la racine du projet avec le type MIME exact.

Exemple pour créer mimetype sans retour à la ligne:

printf "application/epub+zip" > mimetype

Ensuite, créez le fichier META-INF/container.xml qui indique où se trouve le fichier OPF. Ce pointeur est obligatoire et doit préciser le type media-type exact application/oebps-package+xml. Placez ce fichier au chemin META-INF/container.xml et utilisez le contenu suivant:

<?xml version="1.0" encoding="UTF-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
  <rootfiles>
    <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
  </rootfiles>
</container>

Sur Windows, veillez à sauvegarder ces fichiers en UTF-8 sans BOM, en particulier pour mimetype, afin d’éviter des erreurs de validation.

Définir le package OEB: OEBPS/content.opf

Le fichier OEBPS/content.opf est le cœur du package: il expose les métadonnées Dublin Core minimales, déclare les ressources dans le manifest et définit l’ordre de lecture via le spine. Créez le fichier OEBPS/content.opf avec le contenu suivant, en veillant à utiliser une valeur d’identifiant stable (UUID) et une date de modification au format ISO 8601 UTC. Vous pouvez générer un UUID avec la commande uuidgen sous macOS/Linux ou via PowerShell [guid]::NewGuid().

<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/" version="3.0" unique-identifier="pub-id">
  <metadata xmlns:opf="http://www.idpf.org/2007/opf">
    <dc:identifier id="pub-id">urn:uuid:01234567-89ab-cdef-0123-456789abcdef</dc:identifier>
    <dc:title>Mon EPUB minimal</dc:title>
    <dc:language>fr</dc:language>
    <meta property="dcterms:modified">2026-01-03T12:00:00Z</meta>
  </metadata>
  <manifest>
    <item id="css" href="style.css" media-type="text/css"/>
    <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav"/>
    <item id="cover-img" href="cover.jpg" media-type="image/jpeg" properties="cover-image"/>
    <item id="chap1" href="index.xhtml" media-type="application/xhtml+xml"/>
  </manifest>
  <spine>
    <itemref idref="chap1"/>
  </spine>
</package>

Les types media-type doivent être corrects: application/xhtml+xml pour les documents XHTML, text/css pour les feuilles de style, image/jpeg pour une couverture en JPEG. Le document de navigation nav.xhtml est obligatoire en EPUB 3 et il est signalé dans le manifest via l’attribut properties="nav".

Astuce pratique: pour produire automatiquement la date au bon format en bash, utilisez la commande suivante et copiez-la dans dcterms:modified:

date -u +"%Y-%m-%dT%H:%M:%SZ"

La navigation: OEBPS/nav.xhtml

Le fichier de navigation est un document XHTML qui expose la table des matières via un élément nav avec l’attribut EPUB approprié. Créez OEBPS/nav.xhtml et remplissez-le avec ce contenu minimal, en gardant un lien vers la feuille de style et en pointant vers une ancre existante dans le chapitre:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="fr">
<head>
  <meta charset="utf-8"/>
  <title>Table des matières</title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
  <nav epub:type="toc" id="toc">
    <h2>Table des matières</h2>
    <ol>
      <li><a href="index.xhtml#debut">Chapitre 1</a></li>
    </ol>
  </nav>
</body>
</html>

Le manifest de l’OPF référence ce document via l’item portant properties="nav". De nombreux lecteurs s’appuient sur ce fichier pour construire leur interface de table des matières.

Le contenu: OEBPS/index.xhtml et OEBPS/style.css

Créez une page de contenu conforme XHTML, avec une ancre qui correspond à la cible de la navigation. Placez une image et du texte pour vérifier l’affichage dans différents lecteurs. Voici un exemple de chapitre unique:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr">
<head>
  <meta charset="utf-8"/>
  <title>Chapitre 1</title>
  <link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
  <section id="debut">
    <h1>Chapitre 1</h1>
    <p>Ceci est un EPUB minimal construit à la main.</p>
    <figure>
      <img src="cover.jpg" alt="Couverture" />
      <figcaption>Image de couverture intégrée</figcaption>
    </figure>
  </section>
</body>
</html>

Ajoutez une feuille de style simple pour améliorer la lisibilité sans imposer une mise en page rigide. Enregistrez ce CSS dans OEBPS/style.css:

body{ font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; line-height:1.6; }
h1{ font-size:1.6em; margin:0.6em 0; }
figure{ margin:1em 0; }
img{ max-width:100%; height:auto; }

Placez enfin une image de couverture dans OEBPS/cover.jpg. Une hauteur entre 1400 et 1800 pixels est suffisante pour un EPUB reflowable; privilégiez un ratio vertical et une compression JPEG modérée pour garder une taille de fichier raisonnable.

Emballer correctement en .epub (ZIP avec ordre et stockage)

L’emballage détermine la lisibilité de votre EPUB. L’entrée mimetype doit impérativement apparaître en premier dans l’archive ZIP et être stockée sans compression. Les autres dossiers et fichiers peuvent être ajoutés avec compression. À partir du dossier mon-epub, créez l’archive en deux commandes pour garantir l’ordre et les options adéquates.

Exemple avec l’outil zip classique sous macOS/Linux:

# 1) Ajouter mimetype en premier, sans compression (-0), en préservant les métadonnées minimales (-X)
zip -X0 ../mon.epub mimetype

# 2) Ajouter le reste avec compression (-9), récursif (-r), en normalisant les timestamps (-D) pour des builds reproductibles
zip -Xr9D ../mon.epub META-INF OEBPS

Vous pouvez contrôler le résultat en listant le contenu de l’archive et en vérifiant que mimetype est bien la première entrée et que le fichier est reconnu comme une archive ZIP.

unzip -l ../mon.epub
file ../mon.epub

Sous Windows, PowerShell ne permet pas toujours de forcer le mode STORE sur la première entrée. La solution la plus simple consiste à utiliser zip via Git Bash ou WSL, qui respectent les options -0 et -X. Si vous devez rester dans l’écosystème Windows natif, envisagez un script Node.js (voir plus bas) pour contrôler précisément l’ordre et la compression.

Valider avec epubcheck

La validation avec epubcheck est indispensable avant diffusion. Installez l’outil puis exécutez la vérification sur le fichier produit. Sous macOS, l’installation est directe via Homebrew, sinon vous pouvez télécharger le JAR officiel et l’exécuter avec Java.

Exemples d’installation et d’usage:

# macOS
brew install epubcheck

# Exécuter la validation
epubcheck ../mon.epub

Corrigez toute erreur bloquante signalée par epubcheck, notamment une mauvaise valeur de media-type, une référence manquante dans le manifest, un mimetype compressé, ou un chemin invalide. L’objectif est d’obtenir zéro ERROR. Certains avertissements (WARN) peuvent persister sans empêcher la lecture, mais essayez de les comprendre pour garder une bonne compatibilité.

Automatiser le build avec Node.js

Automatiser la création de l’EPUB facilite les itérations et évite les erreurs d’emballage. Avec Node.js, vous pouvez piloter précisément l’ordre et le mode de compression, en positionnant mimetype en premier et en mode non compressé. Initialisez un projet minimal et installez les dépendances nécessaires, puis créez un petit script de build.

Exemples d’initialisation et de script:

npm init -y
npm i yazl glob fs-extra

Créez un fichier build.js à la racine (au même niveau que le dossier mon-epub si vous souhaitez empaqueter depuis l’extérieur, ou adaptez les chemins si vous exécutez depuis mon-epub). Voici une version qui s’exécute depuis le dossier racine contenant les dossiers META-INF et OEBPS:

const { ZipFile } = require('yazl');
const fs = require('fs');
const fse = require('fs-extra');

(async () => {
  const out = fs.createWriteStream('mon.epub');
  const zip = new ZipFile();
  zip.outputStream.pipe(out).on('close', () => console.log('OK: mon.epub'));

  // 1) mimetype en premier et non compressé
  zip.addBuffer(Buffer.from('application/epub+zip'), 'mimetype', { compress: false });

  // 2) Ajouter META-INF et OEBPS
  const addDir = (dir) => {
    for (const entry of fse.readdirSync(dir)) {
      const p = dir + '/' + entry;
      const stat = fs.statSync(p);
      if (stat.isDirectory()) addDir(p);
      else zip.addFile(p, p, { compress: true });
    }
  };
  addDir('META-INF');
  addDir('OEBPS');

  zip.end();
})();

Ajoutez ensuite un script npm pour exécuter la construction et validez le résultat avec epubcheck.

{
  "name": "mon-epub",
  "version": "1.0.0",
  "scripts": {
    "build:epub": "node build.js"
  }
}

Lancez la construction, puis validez:

node build.js
epubcheck mon.epub

Cette approche vous évite les approximations des utilitaires ZIP selon la plateforme et garantit un emballage conforme.

Qualité et compatibilité: points de contrôle rapides

L’accessibilité débute par une structure sémantique propre. Utilisez des balises pertinentes (section, h1, h2), des attributs alt descriptifs pour les images et une hiérarchie de titres cohérente tout au long du document. Un lecteur d’écran tirera pleinement parti d’une telle structure et la navigation s’en trouvera améliorée.

L’encodage doit être uniforme et explicite. Conservez l’UTF-8 partout et déclarez le charset dans chaque document XHTML via la balise meta correspondante. Les fichiers XML doivent inclure la déclaration d’encodage en tête lorsqu’ils sont générés par des outils.

Les chemins des ressources doivent rester relatifs à OEBPS. Évitez absolument les chemins absolus et vérifiez que chaque href ou src correspond à un fichier présent et déclaré dans le manifest. Une référence manquante dans le manifest est une erreur classique repérée par epubcheck.

La couverture est mieux indexée lorsqu’elle est déclarée avec l’attribut properties="cover-image" sur l’item image du manifest. Certains lecteurs l’emploient pour générer des vignettes, des aperçus ou des affichages de bibliothèque, ce qui améliore l’expérience utilisateur.

Enfin, testez votre EPUB sur plusieurs lecteurs pour vérifier l’affichage, la navigation et les polices. Par exemple, essayez Thorium Reader sur desktop, Apple Books sur macOS/iOS et Calibre Ebook Viewer. Chaque moteur de rendu ayant ses subtilités, un test croisé apporte rapidement des retours concrets.

Aller un peu plus loin (optionnel, 5 minutes)

Ajouter des chapitres supplémentaires demande peu de modifications. Créez un nouveau fichier OEBPS/ch2.xhtml, déclarez-le dans le manifest avec un id distinct puis ajoutez un itemref correspondant dans le spine. N’oubliez pas d’étendre la table des matières dans nav.xhtml. Par exemple, ajoutez un second li pointant vers ch2.xhtml#debut2, et assurez-vous que l’ancre existe.

Enrichir les métadonnées donne plus de contexte aux librairies et aux utilisateurs. Ajoutez un auteur via dc:creator, un éditeur via dc:publisher, et des droits via dc:rights. Vous pouvez également indiquer un sujet, une description ou une date de publication. Veillez à conserver la structure Dublin Core et à rester cohérent dans vos champs.

Embarquer des polices améliore la typographie lorsqu’une police système ne convient pas. Ajoutez un fichier WOFF2 dans OEBPS/fonts, déclarez-le dans le manifest avec media-type font/woff2, puis utilisez @font-face dans style.css pour le référencer. Sans surcharger la mise en page, vous pourrez uniformiser l’apparence sur divers appareils.

Inclure des ressources audio ou vidéo est possible si besoin. Déclarez vos médias avec leurs types (par exemple audio/mpeg ou video/mp4), fournissez des alternatives textuelles ou des sous-titres, et testez l’expérience sur des lecteurs compatibles avec EPUB 3 riche. Prévoyez des fallbacks pour les environnements qui ne supportent pas ces médias.

Générer un .zip de prévisualisation pour le web peut accélérer la QA de la couche CSS. Servez simplement le contenu de OEBPS via un petit serveur statique pour valider la structure, la sémantique et la mise en forme en amont du packaging. Un serveur Node.js comme http-server ou une configuration simple de Live Server suffisent pour relire le rendu.

Checklist

À la fin de votre parcours, prenez une minute pour relire tout le contenu et repérer d’éventuelles fautes ou incohérences. Exécutez de nouveau les commandes de construction et comparez la sortie avec un diff pour garantir la reproductibilité. Ouvrez mon.epub dans plusieurs lecteurs pour confirmer le comportement de la navigation et l’affichage de la couverture. Lancez epubcheck et visez un rapport sans erreur, en corrigeant progressivement les avertissements si vous ciblez un large panel de lecteurs. Une fois satisfait, publiez le fichier et conservez votre arborescence comme modèle pour les prochains projets.

Conclusion

Assembler un EPUB 3 à la main est rapide et formateur. En créant les fichiers mimetype et container.xml, en rédigeant un OPF propre, une nav.xhtml claire et un contenu XHTML bien structuré, vous obtenez un livre numérique standard, prêt à être lu et distribué. Cette approche vous donne le contrôle sur chaque détail du packaging OEB, vous permet de diagnostiquer les erreurs avec assurance et constitue une base solide pour automatiser vos productions à l’aide d’un script Node.js. Avec ces fondations, vous pouvez élargir le projet à plusieurs chapitres, enrichir les métadonnées, intégrer des polices et des médias, tout en conservant une validation irréprochable.

Ressources

Pour approfondir les spécifications, la documentation EPUB 3 du W3C est la référence et décrit exhaustivement le format, les rôles du package OPF et des documents de navigation. Vous la trouverez depuis le site du W3C Publishing à l’adresse https://www.w3.org/publishing/.

La documentation d’epubcheck rassemble les règles de validation et les messages d’erreur courants. Le dépôt officiel héberge le binaire et les guides d’utilisation, accessible sur https://github.com/w3c/epubcheck.

Pour les media-types et la compatibilité des fichiers, le registre IANA est utile afin de confirmer les valeurs à employer dans le manifest. La page de référence est disponible sur https://www.iana.org/assignments/media-types/media-types.xhtml.

Si vous cherchez un lecteur de test de bureau fiable et accessible, Thorium Reader maintient une excellente compatibilité EPUB 3, et il est téléchargeable gratuitement depuis https://www.edrlab.org/software/thorium-reader/.

Enfin, pour automatiser la construction ZIP avec un contrôle fin, la bibliothèque yazl utilisée dans l’exemple Node.js est documentée sur https://github.com/thejoshwolfe/yazl, ce qui vous permettra d’aller plus loin dans l’industrialisation de votre chaîne.