Oihana Next UI - 0.48.0

Application logo

Les images

Le composant Picture : son chargement, le montage à l’approche du cadre, le mode qui remplit son parent, du contenu dans les coins et au centre, et ce qu’il affiche faute de source.

Le composant Picture

Une image et son attente

Un paysage au hasard
<Picture
    src="https://picsum.photos/640/480"
    alt="Random landscape"
    width={ 640 }
    height={ 480 }
    className="rounded-box overflow-hidden"
    onLoad={ () => console.log("Loaded!") }
/>

Une galerie en briques

Une galerie qui répartit elle-même ses images en colonnes, selon la largeur disponible.

Image 1 de la galerie
#01
Image 3 de la galerie
#03
Image 5 de la galerie
#05
Image 7 de la galerie
#07
Image 9 de la galerie
#09
Image 11 de la galerie
#11
Image 2 de la galerie
#02
Image 4 de la galerie
#04
Image 6 de la galerie
#06
Image 8 de la galerie
#08
Image 10 de la galerie
#10
Image 12 de la galerie
#12
<Masonry
    columns={ { xs: 2, sm: 2, md: 3, lg: 4 } }
    gap={ 4 }
>
    <Picture
        src="https://picsum.photos/400/600"
        width={ 400 }
        height={ 600 }
        loadingAnimation="ring"
    />
    // More pictures with varying heights...
</Masonry>
💡 Astuce Des hauteurs différentes composent une grille qui coule, sans trou en bas des colonnes.

Le montage à l’approche du cadre

Une image n’entre dans le DOM qu’en arrivant dans le cadre. Faites défiler pour les voir apparaître une à une.

💡 lazyMount ne se confond pas avec le chargement différé du navigateur : le composant entier n’est pas rendu tant qu’il n’est pas visible, ce qui épargne des nœuds du DOM autant que des requêtes.

Avec et sans

Ordinairechargée tout de suite
Chargement ordinaire
lazyMountchargée au défilement

Douze images différées

Chaque image se monte en arrivant dans le cadre, deux cents pixels avant son bord.

#01
#02
#03
#04
#05
#06
#07
#08
#09
#10
#11
#12

lazyRootMargin — L’anticipation du chargement

lazyRootMargin règle de combien de pixels avant le cadre l’image commence à se charger.

lazyRootMargin="0px"au bord
lazyRootMargin="200px"par défaut
lazyRootMargin="500px"bien avant
<Picture
    src="/photo.jpg"
    width={ 400 }
    height={ 300 }
    lazyMount // Only mount when visible
    lazyRootMargin="200px" // Start loading 200px before visible
    lazyThreshold={ 0.1 } // Trigger when 10% is visible
/>
✅ Quand s’en servir ?
  • Les longues galeries — des grilles de vingt images et plus
  • Les listes infinies — du contenu chargé au fil du défilement
  • Les pages lourdes — pour alléger le DOM au premier rendu
  • Le mobile — pour économiser la bande passante et la batterie

Dimensions automatiques et mode « remplir »

💡 Le mode « remplir » rend l’image élastique : elle occupe tout son parent en gardant ses proportions. Ses dimensions naturelles s’affichent en développement.
fill + aspect-video (16:9)
Mode remplir, 16:9
fill + aspect-4/3 (4:3)
Mode remplir, 4:3
fill + aspect-square (1:1)
Mode remplir, 1:1
fill + aspect-21/9 (21:9)
Mode remplir, 21:9

Les quatre cadrages

objectFit="cover"
Cadrage cover
objectFit="contain"
Cadrage contain
objectFit="fill"
Cadrage fill
objectFit="none"
Cadrage none
<div className="relative aspect-video">
    <Picture
        src="/banner.jpg"
        alt="Responsive banner"
        fill // Responsive mode
        objectFit="cover" // or contain, fill, none
        onLoad={ (img) => {
            console.log(img.naturalWidth, img.naturalHeight);
        } }
    />
</div>

Trois mises en pratique

1. Une galerie élastique

Une grille aux proportions égales — ce que demande une série de photographies.

Image 1 de la galerie
Image 2 de la galerie
Image 3 de la galerie
Image 4 de la galerie
Image 5 de la galerie
Image 6 de la galerie
Image 7 de la galerie
Image 8 de la galerie
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
    { photos.map(photo => (
        <div className="relative aspect-square rounded-box overflow-hidden">
            <Picture
                src={ photo.url }
                alt={ photo.title }
                fill
                objectFit="cover"
            />
        </div>
    )) }
</div>

2. Un bandeau d’en-tête

Un bandeau pleine largeur, très étiré — ce que demande un en-tête.

Bandeau d’en-tête

Bienvenue sur Oihana Next UI

Une bibliothèque de composants Next.js, libre

<div className="relative aspect-21/9 w-full">
    <Picture
        src="/hero.jpg"
        alt="Hero"
        fill
        priority // Above the fold
        objectFit="cover"
    />
    <div className="absolute inset-0 ...">
        { /* Overlay content */ }
    </div>
</div>

3. Lire les dimensions

Lire les dimensions naturelles d’une image, pour les traiter ou les afficher.

Lecture des dimensions
Ouvrez la console du navigateur :
  • naturalWidth & naturalHeight — la taille de l’image d’origine
  • width & height — la taille à laquelle elle s’affiche
  • De quoi traiter une image, la valider, ou la mesurer
📸 Image loaded!
Natural dimensions: 1920 x 1080
Displayed dimensions: 480 x 270
<Picture
    src={ userUpload }
    width={ 800 }
    height={ 600 }
    onLoad={ (img) => {
        // Get natural dimensions
        const width = img.naturalWidth;
        const height = img.naturalHeight;
        // Save to database, validate, etc.
        saveDimensions(width, height);
    } }
/>
💡 Ce qu’il faut retenir
  • La galerie — une grille régulière, avec aspect-square et fill
  • Le bandeau — un format large, avec aspect-21/9 et priority
  • Les dimensions — onLoad donne la taille naturelle

Du contenu dans les coins

N’importe quel contenu dans les quatre coins d’une image : pastilles, boutons, icônes, texte.

Une fiche produit
Produit
-30%
$349
$499
En stock
Une photo et ses données
Photo de galerie
📸 Canon EOS R5
⭐ 4.8 · 124 j’aime
Une annonce immobilière
Bien immobilier
À la une
NOUVEAU
À partir de
$1.2M
🛏️ 3 chambres · 🚿 2 salles de bain
Une vignette vidéo
Vidéo
EN DIRECT
⏱️ 12:45
<Picture
    src="/product.jpg"
    width={ 600 }
    height={ 800 }
    // Corner content
    topLeft={ <Badge color="error">-30%</Badge> }
    topRight={ <Button icon={FavoriteIcon} /> }
    bottomLeft={ <div>$349</div> }
    bottomRight={ <Badge>In Stock</Badge> }
    // Optional dimensions
    showDimensions
    dimensionsPosition="bottom-right"
/>
💡 Les emplacements disponibles
  • topLeft — le coin haut gauche — une pastille, une étiquette
  • topRight — le coin haut droit — un bouton d’action
  • bottomLeft — le coin bas gauche — un prix, une donnée
  • bottomRight — le coin bas droit — un état, un appel à l’action
  • showDimensions — affiche les dimensions naturelles de l’image
  • dimensionsPosition — où placer la pastille des dimensions

Du contenu au centre

Du contenu au centre d’une image : un bouton de lecture, un titre en surimpression, un appel à l’action.

Une vignette vidéo
Vignette vidéo
EN DIRECT
⏱️ 45:32
Un titre en surimpression
Titre en surimpression

Les grands espaces

Une sélection de photographies, depuis 1995

Un contenu réservé
Contenu réservé
🔒

Contenu réservé

Abonnez-vous pour accéder aux photos et aux vidéos réservées.

Un aperçu agrandissable
Aperçu
Haute définition
Cliquer pour agrandir
Une sortie à venir
Sortie à venir
BIENTÔT
mars 2026
Un appel à l’action
Appel à l’action
Licence ouverte
🖼️

Des images libres de droits

Mille photographies prêtes à l’emploi, sous licence ouverte.

<Picture
    src="/video-thumbnail.jpg"
    width={ 800 }
    height={ 450 }
    // Center content
    center={
        <Button size="lg" shape="circle">
            <PlayIcon />
        </Button>
    }
    // Can combine with corners
    topRight={ <Badge>LIVE</Badge> }
    bottomLeft={ <div>Duration</div> }
/>
💡 À quoi sert le centre
  • Les boutons de lecture — une vignette vidéo ou sonore et sa commande
  • Les titres — un titre et son bouton, centrés sur l’image
  • Les contenus réservés — une invitation à déverrouiller
  • Les icônes actives — agrandir, prévisualiser, agir
  • Les états — « Bientôt », « Épuisé », et les autres
  • Les appels à l’action — un bouton centré, une promotion

Une image par thème

Deux images, et celle qui s’affiche suit le thème.

💡 Changez de thème : les images suivent.
Un logo selon le thème
Logo

Le thème clair montre la première image, le thème sombre la seconde.

Un bandeau selon le thème
Bandeau selon le thème

Un bandeau qui suit le thème

Un produit et sa variante sombre
Produit
-30%
Une illustration, en mode remplir
Illustration
Premium
<Picture
    src="/logo-light.png" // Light mode image
    dark="/logo-dark.png" // Dark mode image
    alt="Logo"
    width={ 400 }
    height={ 100 }
    // Works with all Picture features
    topLeft={ <Badge>New</Badge> }
    center={ <Button>Click</Button> }
    showDimensions
/>
✅ Ce que ça apporte
  • Une bascule automatique — l’image suit le thème, sans une ligne de JavaScript
  • Rien d’exclu — tout le reste du composant continue — les coins, le centre, le mode remplir
  • Facultatif — sans la propriété dark, le composant se comporte comme avant
  • Une seule image à la fois — c’est le CSS qui décide laquelle se voit
  • Pour quoi — un logo, une illustration, un schéma, un bandeau, un produit

Les animations de l’attente

spinner
Animation spinner
ring
Animation ring
dots
Animation dots
bars
Animation bars
ball
Animation ball
infinity
Animation infinity
<Picture
    loadingAnimation="spinner" // or ring, dots, bars, ball, infinity
/>

Les tailles de l’attente

xs
Taille xs
sm
Taille sm
md
Taille md
lg
Taille lg
xl
Taille xl
<Picture
    loadingSize="xs" // or sm, md, lg, xl
/>

Les couleurs de l’attente

primary
Couleur primary
secondary
Couleur secondary
accent
Couleur accent
error
Couleur error
<Picture
    loadingColor="primary" // Any TextColor
/>

Les images rondes

Portrait 1
Portrait 2
Portrait 3
<Picture
    src="https://i.pravatar.cc/150?img=1"
    alt="Avatar"
    width={ 150 }
    height={ 150 }
    className="rounded-full overflow-hidden"
    imageClassName="object-cover"
/>

Sans attente affichée

Sans attente affichée
<Picture
    showLoading={ false } // Disable loading spinner
/>

Le chargement prioritaire

priority pour les images visibles dès le chargement de la page : un bandeau, tout ce qui est au-dessus de la ligne de flottaison.
Bandeau
<Picture
    priority // Preload this image (disables lazy loading)
    src="/hero-banner.jpg"
/>

Sans aucune source : le repli

Une entité sans image, c’est banal. Privé de src, le cadre montre son fallback au lieu d’une image — et les quatre coins comme le centre continuent de fonctionner, si bien qu’un appelant compose ses surimpressions sans avoir à se demander si une image existe.
AS
AS
une teinte prise dans le nom
BW
BW
un autre nom, une autre teinte
AG
AG
une couleur portée par l’entité
coin
une icône, et un coin par-dessus
<Picture
    fallback      = { <span>{ getInitials( name ) }</span> }
    fallbackColor = { entity.color } // a wash of it behind, the colour itself on the content
    fill
/>