layout-11-hero-card-on-photo

Carte de hero incrustée sur un sol photographique

Poser la coque d'un hero de page en DEUX couches seulement : une photo pleine page qui est le sol de la page — pas un décor de maquette, pas une mise en scène —, et une carte unie qui y est INCRUSTÉE, marges de sol strictement égales à gauche et à droite, rayon discret et ombre descendante qui la fait flotter. Le sol reste une photo : posée sur un aplat de sa propre couleur, la carte perd son bord et le hero n'a plus de sol du tout.

layoutweb1440×900px14 benchmarks

Télécharger le .zip

Le fragment RÉEL, dans son propre document, sur le sol de sa charte — pas une image. Ce que vous voyez est exactement ce que vous collerez.

Employer quand

Hero de page d'accueil ou de landing dont on veut que la photo appartienne à la PAGE et non à une mise en scène du design : la carte porte toute la typographie, la photo n'affleure qu'en cadre autour d'elle. Sert aussi de coque à un écran de couverture web où le contenu doit rester lisible sur une image mouvante.

Éviter quand

La photo est une mise en scène du design (une maquette posée sur un bureau, une ombre d'objet physique, une perspective) : il faut alors la retirer, pas l'incruster — c'est exactement l'arbitrage rendu entre cette référence et ref-08. Écarter aussi quand le contenu doit saigner jusqu'aux bords : ce pattern n'a de sens que si la carte laisse voir son sol sur ses quatre côtés.

Notes

Le pattern tient sur une seule frontière, et elle n'est pas « photo ou pas photo » : c'est **mise en scène du design** contre **fond de la page**. Sur ref-08 la photo montrait la carte posée dans une pièce, avec ombre d'objet physique — elle a été retirée le 30/07 parce qu'elle obligeait à recadrer chaque export. Ici la photo est le sol de la page, à plat, sans perspective : la retirer supprimerait le sujet du pattern. Le benchmark d'écart de fond (sol ≠ carte, ≥ 6 % sur une composante) est la version mesurée de cette frontière — il refuse le cas où quelqu'un remplace la photo par un aplat crème, qui passe tous les autres contrôles et fait pourtant disparaître le bord de la carte. Deux couches, pas trois. Le sol et la carte, et c'est tout. Tout ce qui vient ensuite — la nav, le wordmark, le triptyque — sont des feuilles DANS la carte, pas des couches supplémentaires : les empiler ferait tomber check-deck.mjs, qui compte la profondeur des surfaces. Les marges de sol gauche et droite ne sont pas posées à la main, elles découlent du centrage de la carte : la seule manière de garantir l'égalité sans qu'une correction de taille la casse en silence. Les marges verticales, elles, sont plus SERRÉES que les latérales (12,9 % de la hauteur contre 11 % de la largeur, soit 116 px contre 158) — c'est ce qui empêche la carte de se lire comme un cadre photo centré. `.vl-hcop__card` est livrée VIDE : c'est le slot. Sa marge intérieure (`--vl-margin`, 3,9 % de la largeur de carte) est la seule promesse que la coque tienne à ce qu'on y pose. Le sol est une composition SVG générative, sans URL distante ; ce qui compte pour le pattern est qu'il soit photographique et pleine page, pas son sujet.

Mots-clés

herolandingphotoimageincrustationcarteflottantombrecoqueshellaccueil

Benchmarks — la géométrie, en assertions vérifiables

Rejouables par node bin/check.mjs layout-11-hero-card-on-photo : le pattern se prouve, il ne se croit pas.

assertionmesureattendu
marges de sol gauche et droite ÉGALES : c'est une incrustation, pas une carte poussée dans un coinMath.abs(box('.vl-hcop__card').left - (W - box('.vl-hcop__card').right)) / W≤ 0.002
marge de sol latérale : 11 % de la largeur de pagebox('.vl-hcop__card').left / W0.1097 ± 0.005
marges de sol haute et basse égalesMath.abs(box('.vl-hcop__card').top - (H - box('.vl-hcop__card').bottom)) / H≤ 0.002
marge de sol verticale : 12,9 % de la hauteur de pagebox('.vl-hcop__card').top / H0.1289 ± 0.006
la carte occupe 78 % de la largeur de pagebox('.vl-hcop__card').w / W0.7806 ± 0.008
la carte occupe 74 % de la hauteur de pagebox('.vl-hcop__card').h / H0.7422 ± 0.008
la carte n'est JAMAIS à fond perdu : le sol reste visible sur ses quatre côtésMath.min(box('.vl-hcop__card').left, box('.vl-hcop__card').top, W - box('.vl-hcop__card').right, H - box('.vl-hcop__card').bottom) / W≥ 0.06
le sol couvre TOUTE la page : aucune bande de fond nu autour de la photo(box('.vl-hcop__ground').w * box('.vl-hcop__ground').h) / (W * H)1 ± 0.002
le sol n'est PAS un aplat de la couleur de la carte : sans écart, la carte perd son bord(() => { const p = (s) => (getComputedStyle(document.querySelector(s)).backgroundColor.match(/[\d.]+/g) || []).map(Number); const a = p('.vl-hcop'), b = p('.vl-hcop__card'); return Math.max(Math.abs(a[0]-b[0]), Math.abs(a[1]-b[1]), Math.abs(a[2]-b[2])) / 255; })()≥ 0.06
la carte FLOTTE : une ombre portée est déclaréecs('.vl-hcop__card','boxShadow') === 'none' ? 0 : 11 ± 0.001
l'ombre tombe VERS LE BAS : décalage vertical ≥ 1 % de la hauteur de page(() => { const m = (cs('.vl-hcop__card','boxShadow').match(/-?[\d.]+px/g) || []).map(parseFloat); return m[1] / H; })()≥ 0.01
l'ombre est DIFFUSE, jamais un liseré dur : flou ≥ 2 % de la largeur de page(() => { const m = (cs('.vl-hcop__card','boxShadow').match(/-?[\d.]+px/g) || []).map(parseFloat); return m[2] / W; })()≥ 0.02
le rayon de la carte est un LISERÉ, pas une pilule : ≤ 0,8 % de la largeur de pagenum('.vl-hcop__card','borderTopLeftRadius') / W0.001 → 0.008
scène de HERO WEB au ratio 1,6 — ce n'est pas une slide 16:9W / H1.6 ± 0.01

Le code

fragment — patterns/layout-11-hero-card-on-photo.html Télécharger
<!-- layout-11-hero-card-on-photo — la coque d'un hero de page. Couleurs via --vl-* uniquement.

     DEUX couches, et pas une de plus : le SOL (photo pleine page) → la CARTE. Ce qui viendra
     dans la carte — nav, wordmark, images — ce sont des feuilles décorées, pas des couches.

     Le sol est une PHOTO, jamais un aplat. Une carte crème posée sur un aplat crème n'a plus
     de bord : le hero perd son sol et il ne reste qu'une marge. C'est la seule chose que ce
     pattern doit garantir, et c'est mesuré (écart de fond sol ↔ carte).

     `.vl-hcop__card` est VIDE : ce n'est pas un oubli, c'est le slot. Ce qui s'y posera sera
     ferré sur la marge intérieure de la carte — la seule promesse que la coque tienne à ce qui
     vient après elle (layout-12-nav-three-zone, title-03-wordmark-bottom-left,
     layout-13-image-triptych sur la référence). -->
<div class="vl-hcop">

  <!-- LE SOL — plage : ciel, mer, écume, sable mouillé, sable sec. Composition SVG
       générative : aucune URL distante, rien qui périme. Les lignes de houle sont espacées
       irrégulièrement — un peigne régulier redevient une trame géométrique et la mer meurt. -->
  <svg class="vl-hcop__ground" viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice"
       role="img" aria-label="A wide beach: sky, sea, wet sand and dry sand">
    <defs>
      <linearGradient id="vlhcop-sky" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0" stop-color="var(--vl-ground-sky-hi)"/>
        <stop offset="1" stop-color="var(--vl-ground-sky-lo)"/>
      </linearGradient>
      <linearGradient id="vlhcop-sea" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0" stop-color="var(--vl-ground-sea-lo)"/>
        <stop offset="1" stop-color="var(--vl-ground-sea-hi)"/>
      </linearGradient>
      <linearGradient id="vlhcop-sand" x1="0.2" y1="0" x2="0.8" y2="1">
        <stop offset="0" stop-color="var(--vl-ground-sand-wet)"/>
        <stop offset="0.45" stop-color="var(--vl-ground-sand-dry)"/>
        <stop offset="1" stop-color="var(--vl-ground-sand-wet)"/>
      </linearGradient>
      <filter id="vlhcop-haze"><feGaussianBlur stdDeviation="14"/></filter>
      <filter id="vlhcop-soft"><feGaussianBlur stdDeviation="3.5"/></filter>
      <filter id="vlhcop-grain">
        <feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3"/>
      </filter>
    </defs>

    <rect width="1440" height="900" fill="url(#vlhcop-sky)"/>
    <ellipse cx="1060" cy="196" rx="300" ry="150" fill="var(--vl-ground-sun)"
             filter="url(#vlhcop-haze)" opacity="0.5"/>
    <rect y="330" width="1440" height="248" fill="url(#vlhcop-sea)"/>
    <g fill="var(--vl-ground-foam)" filter="url(#vlhcop-soft)" opacity="0.34">
      <rect y="352" width="1440" height="3"/><rect y="391" width="1440" height="5"/>
      <rect y="447" width="1440" height="3"/><rect y="512" width="1440" height="7"/>
    </g>
    <!-- l'écume : une bande irrégulière, pas un trait — c'est elle qui articule mer et sable -->
    <path d="M0 560 C 190 548 300 578 480 570 C 640 563 720 586 900 576
             C 1080 566 1210 590 1440 574 L 1440 604 C 1200 618 1060 596 900 604
             C 720 613 620 592 470 600 C 300 609 180 584 0 596 Z"
          fill="var(--vl-ground-foam)" filter="url(#vlhcop-soft)" opacity="0.85"/>
    <rect y="578" width="1440" height="322" fill="url(#vlhcop-sand)"/>
    <!-- laisses de marée : des arcs mous, jamais des courbes parallèles -->
    <g fill="var(--vl-ground-sand-wet)" filter="url(#vlhcop-soft)" opacity="0.35">
      <path d="M0 632 C 260 618 420 646 700 634 C 940 624 1150 648 1440 630 L 1440 640
               C 1150 660 940 636 700 646 C 420 658 260 630 0 644 Z"/>
      <path d="M0 726 C 300 706 520 742 820 726 C 1080 712 1240 740 1440 722 L 1440 733
               C 1240 752 1080 724 820 738 C 520 754 300 718 0 738 Z" opacity="0.7"/>
    </g>
    <rect width="1440" height="900" filter="url(#vlhcop-grain)" opacity="0.10"
          style="mix-blend-mode: overlay"/>
  </svg>

  <!-- LA CARTE — incrustée, jamais à fond perdu. Les marges de sol gauche et droite sont
       ÉGALES : c'est ce qui distingue une incrustation d'une carte poussée dans un coin. -->
  <div class="vl-hcop__card"><!-- slot : le contenu du hero --></div>

</div>

<style>
/* La scène est un HERO DE PAGE : 1440 × 900, ratio 1,6 — pas une slide, le 16:9 n'a pas de
   sens ici. `background` porte la dominante du ciel : c'est elle que lit le lint de
   composition, qui ne sait pas échantillonner un SVG. Sans elle, le sol se comparerait à du
   blanc et la carte crème passerait pour une couche 1:1 redondante. */
.vl-hcop {
  position: relative;
  width: 1440px; height: 900px;
  overflow: hidden;
  background: var(--vl-ground-sky-lo);
  display: flex; align-items: center; justify-content: center;
}
.vl-hcop__ground { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* 78 % de la largeur de page. Le centrage par flex est ce qui rend les deux marges de sol
   égales PAR CONSTRUCTION — le pattern ne les pose pas à la main, il les fait découler de la
   taille de la carte. L'ombre est ce qui la fait flotter : sans elle, la carte redevient une
   découpe collée sur le fond. */
.vl-hcop__card {
  position: relative;
  width: 78.056%;   /* 1124 / 1440 */
  height: 74.222%;  /*  668 / 900  */
  padding: var(--vl-margin);
  background: var(--vl-card);
  border-radius: var(--vl-radius-card);
  box-shadow: var(--vl-shadow-card);
}
</style>
tokens de la charte — systems/ref-07-retro-brand-hero.json Télécharger
:root {
  --vl-card: #FBF7EC;
  --vl-bg: #FBF7EC;
  --vl-ink: #1E1B18;
  --vl-accent: #B2201C;
  --vl-on-accent: #FBF7EC;
  --vl-ground-sky-hi: #D7E6EC;
  --vl-ground-sky-lo: #BBD3DE;
  --vl-ground-sun: #F4EFE2;
  --vl-ground-sea-hi: #7FA8BC;
  --vl-ground-sea-lo: #5E8AA0;
  --vl-ground-foam: #EFEAE0;
  --vl-ground-sand-wet: #C7B49A;
  --vl-ground-sand-dry: #E4D5BC;
  --vl-ph-a-hi: #86B0C4;
  --vl-ph-a-lo: #3F6B84;
  --vl-ph-a-crest: #F1EDE3;
  --vl-ph-b-sky: #C9DEE7;
  --vl-ph-b-canvas: #D8442E;
  --vl-ph-b-canvas-lo: #92251C;
  --vl-ph-b-pole: #EDE4D2;
  --vl-ph-c-hi: #EFE1C6;
  --vl-ph-c-lo: #B9A181;
  --vl-radius-card: 6px;
  --vl-radius-photo: 8px;
  --vl-radius-pill: 4px;
  --vl-gap: 12px;
  --vl-margin: 44px;
  --vl-shadow-card: 0 24px 60px rgba(0, 0, 0, 0.18);
}
les métadonnées — patterns/layout-11-hero-card-on-photo.json (télécharger)
{
  "name": "Carte de hero incrustée sur un sol photographique",
  "family": "layout",
  "ref": "ref-07-retro-brand-hero",
  "intent": "Poser la coque d'un hero de page en DEUX couches seulement : une photo pleine page qui est le sol de la page — pas un décor de maquette, pas une mise en scène —, et une carte unie qui y est INCRUSTÉE, marges de sol strictement égales à gauche et à droite, rayon discret et ombre descendante qui la fait flotter. Le sol reste une photo : posée sur un aplat de sa propre couleur, la carte perd son bord et le hero n'a plus de sol du tout.",
  "when_to_use": "Hero de page d'accueil ou de landing dont on veut que la photo appartienne à la PAGE et non à une mise en scène du design : la carte porte toute la typographie, la photo n'affleure qu'en cadre autour d'elle. Sert aussi de coque à un écran de couverture web où le contenu doit rester lisible sur une image mouvante.",
  "avoid_when": "La photo est une mise en scène du design (une maquette posée sur un bureau, une ombre d'objet physique, une perspective) : il faut alors la retirer, pas l'incruster — c'est exactement l'arbitrage rendu entre cette référence et ref-08. Écarter aussi quand le contenu doit saigner jusqu'aux bords : ce pattern n'a de sens que si la carte laisse voir son sol sur ses quatre côtés.",
  "media": [
    "web"
  ],
  "tags": [
    "hero",
    "landing",
    "photo",
    "image",
    "incrustation",
    "carte",
    "flottant",
    "ombre",
    "coque",
    "shell",
    "accueil"
  ],
  "vars": [
    {
      "name": "--vl-card",
      "role": "aplat de la carte incrustée — doit trancher sur le sol, jamais s'y fondre",
      "default": "#FBF7EC"
    },
    {
      "name": "--vl-radius-card",
      "role": "rayon de la carte : un liseré, jamais une pilule",
      "default": "6px"
    },
    {
      "name": "--vl-shadow-card",
      "role": "ombre descendante et diffuse — c'est elle, et elle seule, qui fait flotter la carte",
      "default": "0 24px 60px rgba(0, 0, 0, 0.18)"
    },
    {
      "name": "--vl-margin",
      "role": "marge intérieure de la carte, sur laquelle se ferre tout ce qu'on y pose",
      "default": "44px"
    },
    {
      "name": "--vl-ground-sky-hi",
      "role": "haut du ciel du sol photographique",
      "default": "#D7E6EC"
    },
    {
      "name": "--vl-ground-sky-lo",
      "role": "bas du ciel — et repli opaque de la scène, ce que lit le lint de composition",
      "default": "#BBD3DE"
    },
    {
      "name": "--vl-ground-sun",
      "role": "halo solaire diffusé dans le ciel",
      "default": "#F4EFE2"
    },
    {
      "name": "--vl-ground-sea-hi",
      "role": "mer, près du rivage",
      "default": "#7FA8BC"
    },
    {
      "name": "--vl-ground-sea-lo",
      "role": "mer, au large",
      "default": "#5E8AA0"
    },
    {
      "name": "--vl-ground-foam",
      "role": "écume et lignes de houle",
      "default": "#EFEAE0"
    },
    {
      "name": "--vl-ground-sand-wet",
      "role": "sable mouillé, laisses de marée",
      "default": "#C7B49A"
    },
    {
      "name": "--vl-ground-sand-dry",
      "role": "sable sec",
      "default": "#E4D5BC"
    }
  ],
  "slots": [
    "ground",
    "content"
  ],
  "geometry": {
    "root": ".vl-hcop",
    "frame": [
      1440,
      900
    ],
    "ratios": {
      "card_w_over_frame": 0.7806,
      "card_h_over_frame_h": 0.7422,
      "ground_margin_x_over_frame": 0.1097,
      "ground_margin_y_over_frame_h": 0.1289,
      "card_radius_over_frame": 0.0042,
      "shadow_offset_y_over_frame_h": 0.0267,
      "shadow_blur_over_frame": 0.0417,
      "card_pad_over_card_w": 0.0391
    },
    "type_px": {},
    "pad_ratio": {
      "top": 0,
      "x": 0,
      "bottom": 0
    }
  },
  "benchmarks": [
    {
      "name": "marges de sol gauche et droite ÉGALES : c'est une incrustation, pas une carte poussée dans un coin",
      "measure": "Math.abs(box('.vl-hcop__card').left - (W - box('.vl-hcop__card').right)) / W",
      "max": 0.002
    },
    {
      "name": "marge de sol latérale : 11 % de la largeur de page",
      "measure": "box('.vl-hcop__card').left / W",
      "expect": 0.1097,
      "tol": 0.005
    },
    {
      "name": "marges de sol haute et basse égales",
      "measure": "Math.abs(box('.vl-hcop__card').top - (H - box('.vl-hcop__card').bottom)) / H",
      "max": 0.002
    },
    {
      "name": "marge de sol verticale : 12,9 % de la hauteur de page",
      "measure": "box('.vl-hcop__card').top / H",
      "expect": 0.1289,
      "tol": 0.006
    },
    {
      "name": "la carte occupe 78 % de la largeur de page",
      "measure": "box('.vl-hcop__card').w / W",
      "expect": 0.7806,
      "tol": 0.008
    },
    {
      "name": "la carte occupe 74 % de la hauteur de page",
      "measure": "box('.vl-hcop__card').h / H",
      "expect": 0.7422,
      "tol": 0.008
    },
    {
      "name": "la carte n'est JAMAIS à fond perdu : le sol reste visible sur ses quatre côtés",
      "measure": "Math.min(box('.vl-hcop__card').left, box('.vl-hcop__card').top, W - box('.vl-hcop__card').right, H - box('.vl-hcop__card').bottom) / W",
      "min": 0.06
    },
    {
      "name": "le sol couvre TOUTE la page : aucune bande de fond nu autour de la photo",
      "measure": "(box('.vl-hcop__ground').w * box('.vl-hcop__ground').h) / (W * H)",
      "expect": 1,
      "tol": 0.002
    },
    {
      "name": "le sol n'est PAS un aplat de la couleur de la carte : sans écart, la carte perd son bord",
      "measure": "(() => { const p = (s) => (getComputedStyle(document.querySelector(s)).backgroundColor.match(/[\\d.]+/g) || []).map(Number); const a = p('.vl-hcop'), b = p('.vl-hcop__card'); return Math.max(Math.abs(a[0]-b[0]), Math.abs(a[1]-b[1]), Math.abs(a[2]-b[2])) / 255; })()",
      "min": 0.06
    },
    {
      "name": "la carte FLOTTE : une ombre portée est déclarée",
      "measure": "cs('.vl-hcop__card','boxShadow') === 'none' ? 0 : 1",
      "expect": 1,
      "tol": 0.001
    },
    {
      "name": "l'ombre tombe VERS LE BAS : décalage vertical ≥ 1 % de la hauteur de page",
      "measure": "(() => { const m = (cs('.vl-hcop__card','boxShadow').match(/-?[\\d.]+px/g) || []).map(parseFloat); return m[1] / H; })()",
      "min": 0.01
    },
    {
      "name": "l'ombre est DIFFUSE, jamais un liseré dur : flou ≥ 2 % de la largeur de page",
      "measure": "(() => { const m = (cs('.vl-hcop__card','boxShadow').match(/-?[\\d.]+px/g) || []).map(parseFloat); return m[2] / W; })()",
      "min": 0.02
    },
    {
      "name": "le rayon de la carte est un LISERÉ, pas une pilule : ≤ 0,8 % de la largeur de page",
      "measure": "num('.vl-hcop__card','borderTopLeftRadius') / W",
      "min": 0.001,
      "max": 0.008
    },
    {
      "name": "scène de HERO WEB au ratio 1,6 — ce n'est pas une slide 16:9",
      "measure": "W / H",
      "expect": 1.6,
      "tol": 0.01
    }
  ],
  "notes": "Le pattern tient sur une seule frontière, et elle n'est pas « photo ou pas photo » : c'est **mise en scène du design** contre **fond de la page**. Sur ref-08 la photo montrait la carte posée dans une pièce, avec ombre d'objet physique — elle a été retirée le 30/07 parce qu'elle obligeait à recadrer chaque export. Ici la photo est le sol de la page, à plat, sans perspective : la retirer supprimerait le sujet du pattern. Le benchmark d'écart de fond (sol ≠ carte, ≥ 6 % sur une composante) est la version mesurée de cette frontière — il refuse le cas où quelqu'un remplace la photo par un aplat crème, qui passe tous les autres contrôles et fait pourtant disparaître le bord de la carte.\n\nDeux couches, pas trois. Le sol et la carte, et c'est tout. Tout ce qui vient ensuite — la nav, le wordmark, le triptyque — sont des feuilles DANS la carte, pas des couches supplémentaires : les empiler ferait tomber check-deck.mjs, qui compte la profondeur des surfaces.\n\nLes marges de sol gauche et droite ne sont pas posées à la main, elles découlent du centrage de la carte : la seule manière de garantir l'égalité sans qu'une correction de taille la casse en silence. Les marges verticales, elles, sont plus SERRÉES que les latérales (12,9 % de la hauteur contre 11 % de la largeur, soit 116 px contre 158) — c'est ce qui empêche la carte de se lire comme un cadre photo centré.\n\n`.vl-hcop__card` est livrée VIDE : c'est le slot. Sa marge intérieure (`--vl-margin`, 3,9 % de la largeur de carte) est la seule promesse que la coque tienne à ce qu'on y pose. Le sol est une composition SVG générative, sans URL distante ; ce qui compte pour le pattern est qu'il soit photographique et pleine page, pas son sujet.",
  "id": "layout-11-hero-card-on-photo"
}

À côté