Bilder im Internet/Bilder präsentieren

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Meist werden Bilder nicht nur einzeln, sondern zusammen mit anderen Fotos in einer Bildergalerie präsentiert. In diesem Kapitel lernen Sie, wie Sie Bildergalerien mit HTML und CSS gestalten können.

Zoom bei img:hover?

Ich möchte gerne, dass Bilder durch Überfahren der Maus in Großdarstellung angezeigt werden.

Diese Aufgabenstellung vernachlässigt zwei Aspekte bei Bildergalerien:

  • Auf mobilen Geräten ist der Viewport so klein, dass auf eine Vorschauansicht verzichtet werden kann.
  • Ein Bild sollte sowohl auf mobilen Touchgeräten ohne Tastatur als auch mit der Tastatur, z.B mit der Tab-Taste ( ), ausgewählt werden können.

Während solche Großansichten früher nur mit JavaScript oder jQuery verwirklicht wurden, kamen mit CSS3 und CSS-animation scheinbar einfache CSS-Lösungen auf. Diese stießen aber immer wieder auf Probleme:

  • Bilder können mit :hover auf Mausberührungen reagieren, aber nicht auf ein „Durchtabben“ mit der Tastatur.
  • Bilder, die durch :hover oder Klick in einer Großansicht dargestellt werden, ragen teilweise aus dem Viewport hinaus und sind so nicht sichtbar. Bei heute verpönten, pixelgenauen Layouts mag man mit absoluter Positionierung eine Feinjustierung vornehmen können, auf Mobilgeräten wird dies schnell zur Fummelei.
    Mit JavaScript und der Intersection Observer API könnte man überprüfen, ob sich ein HTML-Element im Viewport befindet und wenn nicht - es entsprechend verschieben.)


Screenshot von mit :hover vergrößerten Bildern, die sich außerhalb des Viewports befinden
Screenshot von mit :hover vergrößerten Bildern, die sich teilweise außerhalb des Viewports befinden

Bilderzoom mit Grid Layout

Dieses Beispiel von Temani Afif[1] ordnet 9 Bilder in einem 3x3-Grid an. Mit :hover oder beim Durchtabben wird das aktive Bild gezoomt und die Bildunterschrift wird sichtbar:

Schritt 1: ein Grid ansehen …
.gallery {
  --size: 10em; /* control the size */
  --gap: 1em;  /* control the gap */
  --zoom: 2;   /* control the scale factor */
  
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(3,auto);
  width: calc(3*var(--size) + 2*var(--gap));
  aspect-ratio: 1;

}

Das Element mit der Klasse gallery erhält mit grid-template-columns drei Spalten ohne Breitenangabe. Diese wird über die width festgelegt, deren Wert mit der calc()-Funktion aus den custom properties für --size und --gap berechnet wird. Mittels der aspect-ratio-Eigenschaft wird diese Breite auch für die Höhe der Galerie übernommen.

Das gezoomte Bild ist nie breiter als die Galerie und bleibt somit immer im Viewport!


Schritt 2: Bilderzoom ansehen …
.gallery figure {
  margin: 0;
  padding: 0;
  position: relative;
}
.gallery > figure img {
  width: 0;
  height: 0;
  min-height: 100%;
  min-width: 100%;
  object-fit: cover;
  cursor: pointer;
  filter: grayscale(80%);
  transition: .35s linear;
}

.gallery > figure:hover img,
.gallery > figure:focus img{
  filter: grayscale(0);
  width:  calc(var(--size)*var(--zoom));
  height: calc(var(--size)*var(--zoom));
}

.gallery figcaption {
	position: absolute;
  	bottom: 0;
	left: 0;
	text-align: center;
	width: 100%;
  	opacity: 0;
	color: white;
	background: rgb(0 0 0 / 0.3);	
}

.gallery figure:hover figcaption,
.gallery figure:focus figcaption {
  opacity: 1;
}

Im Originalzustand füllen alle Bilder ihr jeweiliges figure-Element aus. Mit der CSS filter-Eigenschaft wird ein Grauschleier grayscale(.8) über die Bilder gelegt. Die Figcaption erhält einen dunklen Hintergrund und weiße Schrift, bleibt durch opacity: 0 aber unsichtbar.

Bei :hover oder dem Antabben wird nun das Bild mit grayscale(0) wieder farbig; die Breite und Höhe werden über den --zoom-Wert vergrößert. Die Änderung der Eigenschaftswerte erfolgt mit transition als weicher Übergang mit einer Dauer von 0.35s.

Auch die Figcaption wird nun eingeblendet.

Bildunterschriften

Um Bildern eine passende Erklärung oder Bildunterschrift zu geben ist das figcaption-Element in Verbindung mit dem figure-Container ideal. Es ist vor allem aus Gründen der Semantik den leider immer noch häufig anzutreffenden Lösungen mit verschachtelten div-Elementen vorzuziehen.

Präsentieren eines Bildes mit figure und figcaption ansehen …
<figure>
	<img src="lauf-1.jpg" alt="Lauf an der Pegnitz - Nürnberger Tor">
	<figcaption>Lauf an der Pegnitz - Nürnberger Tor</figcaption>
</figure>

Als Container für das img-Element und die figcaption dient ein figure-Element.

Nur mit dem default-CSS der Browser sieht das Ergebnis zunächst einmal wenig ansprechend aus. Deshalb setzen wir unsere Vorstellungen mit ein wenig CSS um:

CSS für figure und figcaption ansehen …
figure {
  position: relative;
  margin: 0;
  padding: .5em;
  width: 100%;
  border: thin solid gainsboro;
  background: white;
  width: 100%;
}


@media (min-width: 25em) {
  figure {
    width: 20em;
    float: right;
  }
}

figcaption {
  padding: .8em;
  text-align: center;
}

Hier werden einige Einstellungen festgelegt, die erst später wichtig werden:

Mehrere Bilder nebeneinander

Während in Fließtexten oft ein einzelnes Bild integriert ist, will man häufig mehrere Bilder nebeneinander präsentieren. Das figure-Element kann auch verschachtelt werden:

Präsentieren mehrerer Bilder mit verschachtelten figure-Elementen ansehen …
<figure id="gallery">
  <figcaption>Ansichten von Lauf an der Pegnitz</figcaption>

  <figure>
    <img src="//wiki.selfhtml.org/images/a/a6/Lauf-1.jpg" alt="Lauf an der Pegnitz - Nürnberger Tor">
    <figcaption>Nürnberger Tor</figcaption>
  </figure>

  <figure>
    <img src="//wiki.selfhtml.org/images/4/4a/Lauf-2.jpg" alt="Lauf an der Pegnitz - Pegnitz">
    <figcaption>Brücke über die Pegnitz</figcaption>
  </figure>

  <figure>
    <img src="//wiki.selfhtml.org/images/2/24/Lauf-3.jpg" alt="Lauf an der Pegnitz - Nürnberger Tor">
    <figcaption>Mauermühle und Judenturm</figcaption>
  </figure></figure>

Um die einzelnen Bilder nebeneinander zu positionieren, gibt es mehrere Möglichkeiten in CSS:

  • Die figure-Elemente sind Block-Elemente, die mit display: inline-block; nebeneinander positioniert werden können
    → dafür müssen sie dann passende Breiten und Abstände erhalten.
  • ein ähnlicher Effekt ist mit flexbox möglich. Hier kann man mit justify-content noch bestimmen, wie ein einzelnes Kindelement in der letzten Zeile positioniert wird.
  • mit Grid Layout wird das Elternelement zum Grid Container. Es kann eine feste Spaltenanzahl festgelegt werden, es ist aber auch möglich Raster implizit zu erzeugen, die durch den auto-placement-Algorithmus Rasterelemente automatisch auf den verfügbaren Platz verteilen.
CSS-Einstellungen
#gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));
  gap: 1em;
}

#gallery > figcaption {
  grid-column: 1 / -1;
}

Um im CSS ein figure figure zu vermeiden, geben wir der Bildergalerie eine ID mit Namen gallery.

Folgende Einstellungen sind wichtig:

  • display: grid: erzeugt das Raster
  • grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));: erzeugt Rasterlemente, die zwischen 15em und einem Bruchteil des verfügbaren Platzes breit sind.
  • gap: 1em;: erzeugt einen Abstand zwischen den Rasterelementen, aber nicht außen.

Einziges Problem ist die figcaption der gesamten Galerie. Ohne weitere Festlegungen würde sie das erste Rasterlement links neben dem ersten Bild einnehmen. Mit …

  • grid-column: 1 / -1; erstreckt es sich aber über die gesamte Breite von der ersten bis zur letzten (-1 = von rechts gezählt) Rasterlinie

Einschwebende Bildunterschriften

Normalerweise ist figcaption unterhalb des img im figure-Elternelement positioniert. Wir wollen es jetzt über den unteren Bildrand positionieren. Damit das Bild noch erkennbar bleibt, soll die Bildunterschrift einen durchscheinenden Hintergrund bekommen:

absolute Positionierung der Bildunterschrift ansehen …
#gallery figure {
  position: relative;
}

figure img {
  width: 100%;
  display: block;
} 

#gallery > figure > figcaption {
  position: absolute;
  bottom: 0;
  width: 100%;
  line-height: 3em;
  color: white;
  background: rgb(0 0 0 / .3);
}

Zuerst müssen wir
a #gallery figure relativ und
b #gallery > figure > figcaption absolut positionieren.

Danach wird figcaption mit bottom: 0; unten platziert.

Beachten Sie: Damit bottom: 0; auch wirklich mit dem figure, bzw. img-Element unten bündig abschließt, muss ebenfalls img {display: block;} festgelegt werden.

Folgende Einstellungen sind noch wichtig:

  • width: 100%;: sorgt dafür, dass die Bildunterschrift über die gesamte Breite geht.
  • color: white;: der Text wird weiß,
  • background: black;: der Hintergrund ist als schwarzer, bzw. grauer Balken sichtbar.
  • opacity: 0.3;: Der Hintergrund wird durchscheinend. Dies gilt aber auch für den Text, sodass ein zu niedriger Wert < 0.3 fast nicht lesbar ist.

Der Hover-Effekt

Trotz durchscheinendem Hintergrund liegt nun ein Balken über unserem Bild. Wir können diesen im Normalfall verschwinden lassen und erst bei :hover bzw. :focus einschweben lassen:

einschwebende Bildunterschrift
#gallery > figure > figcaption {
  opacity: 0;
  bottom: -3em;
  transition: all 1s ease;
}

#gallery > figure:focus > figcaption,
#gallery > figure:hover > figcaption {
  opacity: 1;
  bottom: 0;
}

Im mittleren Bild wird die Bildunterschrift im Normalzustand durch bottom: -3em; unterhalb des Rands positioniert. opacity: 0 verhindert, dass die Bildunterschrift sichtbar ist.

Erst bei :hover bzw. :focus wird die Bildunterschrift mit opacity: 1; sichtbar und durch bottom: 0; an den unteren Rand geschoben.

Das overflow: hidden; des figure-Element verhindert, dass die Bildunterschrift schon außerhalb des Bildes zu sehen ist.

Alternativen ansehen …
#gallery > figure.mitte > figcaption {     
  width: 0;
  left: 50%;
} 
	  
#gallery > figure.rechts > figcaption {      
  width: 0;
  bottom: 50%;
  left: 50%;
  overflow: hidden;
}

Die mittlere Bildunterschrift hat zusätzlich eine Breite von 0. Bei :hover oder :focus dehnt sich die Bildunterschrift aus der Mitte heraus in ihre Originalposition.

Die rechte Bildunterschrift entspringt in der Mitte des Bildes und schiebt sich dann nach unten.

Im html haben die figure-Elemente das Attribut tabindex=0 erhalten, damit sie für Tastaturbenutzer fokussierbar werden.

Wo kommt das Fragezeichen her?

Damit man überhaupt weiß, dass es eine (im Normalfall ja nicht sichtbare) Bildunterschrift gibt, wird mittels Pseudoelement ::before ein Fragezeichen im linken unteren Bildrand platziert.

einschwebende Bildunterschrift
#gallery figure::before { 					
  content: "?"; 
  position: absolute; 
  bottom: 1em;
  left: 1em;
  background: white; 
  color: black;
  opacity: .7;
  width: 1.5em;
  height: 1.5em;
  border-radius: 1em;
  text-align: center;
  font-size: 1.5em;
  line-height: 1.5em;
  transition: all 1s ease;
}

#gallery figure:focus:before,
#gallery figure:hover:before {
  opacity: 0;
}

Sobald der Benutzer mit der Maus über das Bild fährt oder das Bild focussiert, verschwindet es wieder. Damit dieser Wechsel nicht zu abrupt erscheint, legen wir mit transition weiche Übergänge fest.

Siehe auch

Popover

Die open-ui.org hat es sich zur Aufgabe gemacht, für solche UI-Elemente optimierte Modelle zu entwerfen und diese zur Standardisierung einzureichen.[2]

Mit der neuen Popover API[3][4] können Sie schnell und einfach Popups und Lightboxen erstellen, die diese Funktionalitäten bereits browserseitig mitbringen. Es ist kein kompliziertes CSS oder gar JavaScript nötig!

HTML: Bildergalerie mit Popover ansehen …
<ul id="galerie">
	<li><button popovertarget="image1"><img src="dummy-1.jpg" alt="Spaß in der Sonne"></button></li>
	<li><button popovertarget="image2"><img src="dummy-2.jpg" alt="Berg im Morgennebel"></button></li>
	<li><button popovertarget="image3"><img src="dummy-3.jpg" alt="Spaß in der Sonne"></button></li>
	<li><button popovertarget="image4"><img src="dummy-4.jpg" alt="Korallenriff"></button></li>
	<li><button popovertarget="image5"><img src="dummy-5.jpg" alt="Morgensonne am Gardasee"></button></li>
	<li><button popovertarget="image6"><img src="dummy-6.jpg" alt="Via Appia, Rom"></button></li>    
</ul>   
  <figure id="image1" popover>
    <img src="dummy-1.jpg" alt="Spaß in der Sonne">
    <figcaption>Spaß in der Sonne</figcaption>
</figure>
<figure id="image2" popover> <img src="//wiki.selfhtml.org/images/e/e7/Dummy-2.jpg" alt="Berg im Morgennebel">
	<figcaption>Berg im Morgennebel</figcaption>
</figure>
……

Die Galerie besteht aus einer unsortierten Liste. So sind die Bilder als zusammengehörende Teilelemente erkennbar.

Die Thumbnails befinden sich innerhalb von Button-Elementen, die über das popovertarget-Attribut mit der id des Popovers verbunden sind. Als Buttons sind sie mit ihrem Standardverhalten sowohl mit Maus, als auch per Touch und Tastatur anwählbar.

Das Popover besteht aus einem figure-Element mit einem popover-Attribut. In diesem Container befinden sich das Bid mit alt-Attribut und einer Bildunterschrift in einer figcaption.

Die browsereigene Darstellung der Buttons ähnelt dem Rahmen eines Dias, sodass der Effekt einer Bildergalerie passend dargestellt wird. Jetzt muss nur das Popover formatiert werden:

Darstellung mit CSS ansehen …
[popover] {
  background: lightyellow;
  border: thin solid yelow;
  max-width: 20em;
  padding: 1rem;
  margin: 2rem auto;
}
 
img {
  padding: 0;
  margin: 0;	
  width: 100%;  /* Bild passt sich an verfügbaren Raum an */
}

figcaption {
  text-align: center;
}

Die figure-Elemente enthalten alle das boolesche popover-Attribut. Über den Attributselektor [popover]erhalten diese Elemente nun folgende Formatierung:

  • einen hellgelben Hintergund und einen gelben Rand
  • max-width: 20em;: eine maximale Breite von 20em; damit 4k-Bilder nicht den Viewport sprengen.


Beachte: Die Popover API funktioniert (Stand April 2024) in allen Browsern! Der firefox untersützt es seit Version 125, deshalb sind die Beispiele für ältere Versionen vorerst mit einem Polyfill ausgestattet[5]:
<script
  src="https://cdn.jsdelivr.net/npm/@oddbird/popover-polyfill@latest"
  crossorigin="anonymous"
  defer
></script>

Fazit: Na ja!

Dieses Beispiel hat Stärken und Schwächen:

+ immer oberhalb des Inhalts

+ immer im Viewport

+ nur HTML, kein JavaScript nötig

Niemand klickt ein Bild groß, dann klein und dann das nächste wieder groß - Warum gibt es keinen weiter-Button?

HTML wird schnell zu umfangreich, warum sollte das nicht durch JavaScript benutzerfreundlicher angelegt werden?

Deshalb zeigen wir im nächsten Kapitel, wie Sie eine komfortable Lightbox mit Bildwechsler bauen können.


Siehe auch

CSS-Grid-and-Custom-Shapes.jpg

Temani Afif zeigt auf css-tricks, wie man interessante Formen mit Grid Layout zu geometrischen Mustern anordnet:

CSS Grid and Custom Shapes, Part 1 von Temani Afif, 15.08.2022

Slanted-images-by-eric-meyer.png

Eric Meyer zeigt, wie man mit clip-path Bilder anschrägt und nebeneinander positionieren kann:

Flexible Captioned Slanted Images von Eric Meyer (24ways.org)

Weblinks

  1. Zooming Images in a Grid Layout von Temani Afif, 8. Aug 2022
  2. open-ui.org: Popover API (Explainer)
  3. WHATWG: 6.12 The popover attribute
  4. MDN: Popover API
  5. Popover Attribute Polyfill (github.com)