Galerie w Hugo

Prosty sposób na wyświetlenie obrazów w postaci ładnych galerii bez niszczenia markdown na stronie opartej o Hugo.
Zawartość

Podczas migracji z WordPress do Hugo stanąłem przed nie lada wyzwaniem, jeżeli chodzi o galerię zdjęć.

Otóż Hugo przetwarza pliki zapisane w markdown na statyczne strony HTML. W podstawowej konfiguracji każde jedno zdjęcie wstawiane jest jako pełno-wymiarowy obraz, który następnie może być ogarnięty poprzez odpowiednie style CSS, aby wyświetlić go tak jak będziemy chcieli.

A co jeżeli chcemy wstawić zdjęcia w postaci galerii? Na przykład jedno koło drugiego lub 3 na górze 2 na dole?


W internecie możesz znaleźć sporą liczbę wpisów na temat jak użyć shortcodes w Hugo w celu osiągnięcia zamierzonego efektu.

Większość z nich niestety opiera się na wprowadzeniu części tych kodów do markdown, psując je w ich domyślnej formie.

I tak zamiast typowego markdown:

![Tekst alternatywny](/images/obrazek.jpg)

Zachęcają oni do używania niniejszego odpowiednika:

{{< img src="images/obrazek.jpg" >}}

W moim przypadku totalnie sobie nie wyobrażam przechodzenia raz jeszcze przez wszystkie wpisy na mojej stronie i zmienianie odnośnika ![]() na coś w stylu {{< img src="" >}}. Wystarczy, że musiałem poprawić wszystkie odnośniki raz, jak przenosiłem je z WordPressa podczas migracji do Hugo.

Zastosowanie rozwiązania proponowanego przez praktycznie wszystkich powoduje utratę podstawowej uniwersalności używania markdown.

A co, gdy zamiast Hugo będziemy chcieli używać w przyszłości coś innego? Po raz kolejny będziemy musieli przejść przez wszystkie wpisy, zmieniając wszystkie odnośniki do zdjęć? Po to przechodziliśmy na markdown ab tego nie robić. Nie dziękuję!

Postanowiłem przyjrzeć się innemu zastosowaniu shortcodes który nie psuje domyślnego markdown w jego podstawowej formie, pozwalający jednocześnie podejrzeć go w formie preformatowanej (preview) w dowolnym edytorze obsługującym tego typu sposób formatowania tekstu (w moim przypadku iA Writer).


Shortcode z markdown

Otóż Hugo obsługuje shortcodes wraz z markdown.

Shortcodes z markdown w można rozpoznać po tym, że zaczyna się one od {{% a nie {{< .

W skrócie, zdjęcia, które chcemy umieścić w postaci galerii, wystarczy otoczyć shortcodem z markdown, który zrobi resztę za nas.

Shortcode o którym mowa w moim przypadku wygląda następująco (w pliku używającym markdown - wpis.md).

{{% gallery 2x2 %}}

![Tekst alternatywny Obrazek 1](/images/obrazek1.jpg)
![Tekst alternatywny Obrazek 2](/images/obrazek2.jpg)

{{% /gallery %}}

Mój shortcode składa się z nazwy (gallery) oraz parametru – zmiennej (2x2), które wytłumaczę dalej.

Nazewnictwo jest dowolne.

Całość, aby działała, zapisana jest w pliku gallery.html (również dowolne) w folderze layouts/shortcodes/ w motywie strony.

Plik gallery.html zawiera następujący kod:

<div class="gallery_{{ .Get 0 }}">
  {{ .Inner }}
</div>

Jak zapewne się domyślacie, element {{% gallery 2x2 %}} w trakcie generowania strony zastąpiony jest przez <div class="gallery_{{ .Get 0 }}"> a ostatni {{% /gallery %} przez zamykający </div>.

Część pomiędzy {{ .Inner }} odpowiada za pobranie zawartości, która wstawiona jest pomiędzy oba elementy. Jako że ten shortcode wykorzystuje markdown, elementy ![]() zostaną wygenerowane w postaci <img src="" alt=""> zgodnie z podstawową zasadą.

Całość będzie wyglądać mniej więcej tak:

<div class="gallery_{{ .Get 0 }}">
	<p><img src="images/obrazek1.jpg" alt="Tekst alternatywny Obrazek 1"></p>
	<p><img src="images/obrazek2.jpg" alt="Tekst alternatywny Obrazek 2"></p>
</div>

Nie wspomniałem jeszcze, czym jest {{ .Get 0 }} w tym kodzie.

Otóż {{ .Get 0 }} odpowiada za parametr w naszym shortcode, czyli w {{% gallery 2x2 %}} jest nim 2x2.

I tak ostatecznie będzie wyglądało to tak:

<div class="gallery_2x2">
	<p><img src="images/obrazek1.jpg" alt="Tekst alternatywny Obrazek 1"></p>
	<p><img src="images/obrazek2.jpg" alt="Tekst alternatywny Obrazek 2"></p>
</div>

Myślę, że już wiesz, do czego zmierzam.

Jeżeli nasze obrazy otoczone są przez klasę CSS gallery_2x2 wystarczy zdefiniować, co ta klasa będzie robiła.

W moim (uproszczonym) przypadku wygląda to następująco:

div.gallery_2x2 p img {
  float: left;
  max-width: 50%;
}

Dzięki czemu oba obrazki zostaną wyświetlone w szerokości nie większej niż 50% do zawartości okna, każde obok siebie.

W domyślnej formie, oba obrazy wyświetlane będą, bazując na pełnowymiarowym pliku, co nie jest dobre ze względu na SEO oraz prędkości ładowania się strony, szczególnie na wolnych łączach. W tym calu należy zastosować generowane dynamicznie obrazy o różnych rozdzielczościach z wykorzystaniem wbudowanej w Hugo opcji .Resize oraz standardowego loading="lazy" obsługiwanego przez wszystkie obecne przeglądarki. O tym, jak to osiągnąć innym razem.

I takim sposobem mamy galerię w formacie 2x2.

A co w przypadku 3x3?

Moja galeria 3x3 wygląda (prawie) następująco:

div.gallery_3x3 p img {
  float: left;
  max-width: 33%;
}

Na swojej stronie czasami wrzucam zdjęcia, które są zrzutami ekranu, zrobionymi w pozycji pionowej a niżeli poziomej – horyzontalnej, wówczas używam nieco innych parametrów 2v2 i odpowiedniego stylu div.gallery_2v2 p img.

Całe nazewnictwo (jak już wspomniałem) jest dowolne, nie ma tutaj żadnego narzutu.

Nadal tam, gdzie będę chciał, aby poszczególne obrazy wyświetlały się w postaci galerii, będę musiał wyedytować plik markdown dodając {{% gallery 2x2 %}} i {{% /gallery %}} jednakże jest to znacznie rozsądniejsze zastosowanie a niżeli niszczenie markdown i zastępowanie go czymś mniej kompatybilnym ({{< img src="" >}}) z innymi statycznymi generatorami, które są lub mogę pojawić się w przyszłości.


Kod nie działa!

Niestety, powyższe rozwiązanie nie działa od tak.

Wstawianie kodu HTML podczas generowania strony z pliku markdown uważane jest za niebezpieczne, gdyż ktoś może umieścić w nim złośliwy kod, który będzie wykonywany na danej stronie.

W związku z tym nasz <div class="gallery_2x2"> zostanie domyślnie zmieniony na <!-- raw HTML omitted -->.

W pełni świadomi ryzyka dodajemy następującą opcję do naszego pliku konfiguracyjnego Hugo config.toml aby temu zapobiec.

[markup]
  [markup.goldmark]
    [markup.goldmark.renderer]
      unsafe = "true"

Efekt możecie ocenić w moim wpisie Recenzja podróbki opaski Pride 2020 do Apple Watch.

Powyższe rozwiązanie nie wygeneruje nam inteligentnych galerii mozaikowych, do których przyzwyczaił nas JetPack w Wordpress, ale od czegoś trzeba zacząć.

A bez użycia float?

Aktualizacja 03/04/2021

Używanie float w CSS ma swoje plusy, ale również może powodować szereg niepożądanych skutków ubocznych. W związku z tym postanowiłem sprawdzić, czy ten sam efekt otrzymam z użyciem opcji flex popularnej w tak zwanym flexbox.

Otóż, mój CSS wyglądał następująco:

div.gallery_2x2 p img {
  float: left;
  max-width: 48%;
  padding: 0 1% 2% 1%;
}

div.gallery_2v2 p img {
  float: left;
  max-width: 48%;
  padding: 0 1% 2% 1%;
}

div.gallery_3x3 p img {
  float: left;
  max-width: 31%;
  padding: 0 1% 2% 1%;
}

Z wykorzystaniem flex przedstawił się następująco:

div.gallery_2x2,
div.gallery_2v2,
div.gallery_3x3 {
 display: flex;
 flex-wrap: wrap;
}

div.gallery_2x2 p {
  width: 48%;
}

div.gallery_2v2 p {
  width: 48%;
}

div.gallery_3x3 p {
  width: 31%;
}

Efekt końcowy praktycznie niezauważalny bez użycia float a jednocześnie bardziej przejrzysty.

Aby jednak flexbox działał jak należy, pomiędzy zdjęciami w markdown musi być odstęp.

Dla przykładu poniższe nie działa

{{% gallery 2x2 %}}

![Tekst alternatywny Obrazek 1](/images/obrazek1.jpg)
![Tekst alternatywny Obrazek 2](/images/obrazek2.jpg)

{{% /gallery %}}

Natomiast to działa

{{% gallery 2x2 %}}

![Tekst alternatywny Obrazek 1](/images/obrazek1.jpg)

![Tekst alternatywny Obrazek 2](/images/obrazek2.jpg)

{{% /gallery %}}

Pozdrawiam.

Komentarze
Kategorie