Rupert Angermeier2023-08-30T00:00:00Zhttps://ngrmr.atRupert Angermeierr@ngrmr.at2023 Balkan2023-08-30T00:00:00Zhttps://ngrmr.at/cycling/2023-balkan/<h1>2023 Balkan</h1>
<p>Lukas, Paul and me had been talking about a joint cycling tour for years, but every summer we face the issue of finding a week where all three of us have spare vacation time. We had the same issue this year, but we could at least find 4 days for a joint trip. I could extend this by ten days for a full 2 weeks of cycling.</p>
<h2>Route</h2>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/_DUsgyHX-Y-480.avif 480w, https://ngrmr.at/img/_DUsgyHX-Y-826.avif 826w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/_DUsgyHX-Y-480.jpeg 480w, https://ngrmr.at/img/_DUsgyHX-Y-826.jpeg 826w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Map of south-eastern europe showing my route. Starting from southern hungary it leads through Serbia, Montenegro, Albania and ends in North Macedonia." title="Map of south-eastern europe showing my route. Starting from southern hungary it leads through Serbia, Montenegro, Albania and ends in North Macedonia." loading="lazy" decoding="async" src="https://ngrmr.at/img/_DUsgyHX-Y-480.jpeg" width="826" height="600" /></picture></p>
<p>We boarded the train from Vienna to Szeged on monday, August the 14th, where we arrived in the late afternoon.<br />
Our first stop was Ada, Serbia. On the second day we continued along river Tisa and reached Novi Sad, entering the city through its land fill. The next day we crossed the hills south of the Danube, passed though Sremska Mitrovica from where we followed river Save down to Šabac. From there my 2 companions returned by bus to Vienna and I continued to ride south on my own.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/1p3ZEmg9GZ-480.avif 480w, https://ngrmr.at/img/1p3ZEmg9GZ-1024.avif 1024w, https://ngrmr.at/img/1p3ZEmg9GZ-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/1p3ZEmg9GZ-480.jpeg 480w, https://ngrmr.at/img/1p3ZEmg9GZ-1024.jpeg 1024w, https://ngrmr.at/img/1p3ZEmg9GZ-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Waiting at the hungaro-serbian border." title="Waiting at the hungaro-serbian border." loading="lazy" decoding="async" src="https://ngrmr.at/img/1p3ZEmg9GZ-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/o5pSxu--Sn-480.avif 480w, https://ngrmr.at/img/o5pSxu--Sn-1024.avif 1024w, https://ngrmr.at/img/o5pSxu--Sn-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/o5pSxu--Sn-480.jpeg 480w, https://ngrmr.at/img/o5pSxu--Sn-1024.jpeg 1024w, https://ngrmr.at/img/o5pSxu--Sn-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Passing a shepherd with his sheep" title="Passing a shepherd with his sheep" loading="lazy" decoding="async" src="https://ngrmr.at/img/o5pSxu--Sn-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/-UNSipywdw-480.avif 480w, https://ngrmr.at/img/-UNSipywdw-1024.avif 1024w, https://ngrmr.at/img/-UNSipywdw-2464.avif 2464w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/-UNSipywdw-480.jpeg 480w, https://ngrmr.at/img/-UNSipywdw-1024.jpeg 1024w, https://ngrmr.at/img/-UNSipywdw-2464.jpeg 2464w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Climbing our first mountain." title="Climbing our first mountain." loading="lazy" decoding="async" src="https://ngrmr.at/img/-UNSipywdw-480.jpeg" width="2464" height="3280" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/fcXqfFg4lD-480.avif 480w, https://ngrmr.at/img/fcXqfFg4lD-1024.avif 1024w, https://ngrmr.at/img/fcXqfFg4lD-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/fcXqfFg4lD-480.jpeg 480w, https://ngrmr.at/img/fcXqfFg4lD-1024.jpeg 1024w, https://ngrmr.at/img/fcXqfFg4lD-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Paul emerging from the shrubbery, pushing his bike." title="Paul emerging from the shrubbery, pushing his bike." loading="lazy" decoding="async" src="https://ngrmr.at/img/fcXqfFg4lD-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/llXkmr1xyw-480.avif 480w, https://ngrmr.at/img/llXkmr1xyw-1024.avif 1024w, https://ngrmr.at/img/llXkmr1xyw-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/llXkmr1xyw-480.jpeg 480w, https://ngrmr.at/img/llXkmr1xyw-1024.jpeg 1024w, https://ngrmr.at/img/llXkmr1xyw-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Paul staring at a huge plate filled with grilled meat and sausages." title="Paul staring at a huge plate filled with grilled meat and sausages." loading="lazy" decoding="async" src="https://ngrmr.at/img/llXkmr1xyw-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/TlEPiYhHpP-480.avif 480w, https://ngrmr.at/img/TlEPiYhHpP-1024.avif 1024w, https://ngrmr.at/img/TlEPiYhHpP-2638.avif 2638w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/TlEPiYhHpP-480.jpeg 480w, https://ngrmr.at/img/TlEPiYhHpP-1024.jpeg 1024w, https://ngrmr.at/img/TlEPiYhHpP-2638.jpeg 2638w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Lukas crossing the bridge over river Save in Sremska Mitrovica." title="Lukas crossing the bridge over river Save in Sremska Mitrovica." loading="lazy" decoding="async" src="https://ngrmr.at/img/TlEPiYhHpP-480.jpeg" width="2638" height="3518" /></picture><picture><source type="image/avif" srcset="https://ngrmr.at/img/YdWNjun7_4-480.avif 480w, https://ngrmr.at/img/YdWNjun7_4-1024.avif 1024w, https://ngrmr.at/img/YdWNjun7_4-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/YdWNjun7_4-480.jpeg 480w, https://ngrmr.at/img/YdWNjun7_4-1024.jpeg 1024w, https://ngrmr.at/img/YdWNjun7_4-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Paul and Lukas rolling on the dam along river Tisa." title="Paul and Lukas rolling on the dam along river Tisa." loading="lazy" decoding="async" src="https://ngrmr.at/img/YdWNjun7_4-480.jpeg" width="4032" height="3024" /></picture></p>
<p>The next days I crossed a lot of mountains, visited the cities Valjevo, Kosjeric, Užice, Zlatibor and Nova Varoš. I crossed the border to Montenegro on a gravel road in the Kamena Gora nature reservation area between two hail storms. I stayed one night in Berane in Montenegro and the following day I crossed the mountains to Albania and went down the Cemi and Kiri valleys to Shkodra.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/InJxZFVBkD-480.avif 480w, https://ngrmr.at/img/InJxZFVBkD-1024.avif 1024w, https://ngrmr.at/img/InJxZFVBkD-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/InJxZFVBkD-480.jpeg 480w, https://ngrmr.at/img/InJxZFVBkD-1024.jpeg 1024w, https://ngrmr.at/img/InJxZFVBkD-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Gravel roads near Valjevo" title="Gravel roads near Valjevo" loading="lazy" decoding="async" src="https://ngrmr.at/img/InJxZFVBkD-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/P8XerwTERs-480.avif 480w, https://ngrmr.at/img/P8XerwTERs-1024.avif 1024w, https://ngrmr.at/img/P8XerwTERs-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/P8XerwTERs-480.jpeg 480w, https://ngrmr.at/img/P8XerwTERs-1024.jpeg 1024w, https://ngrmr.at/img/P8XerwTERs-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Crossing a stream." title="Crossing a stream." loading="lazy" decoding="async" src="https://ngrmr.at/img/P8XerwTERs-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/oueZ7gnOk0-480.avif 480w, https://ngrmr.at/img/oueZ7gnOk0-1024.avif 1024w, https://ngrmr.at/img/oueZ7gnOk0-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/oueZ7gnOk0-480.jpeg 480w, https://ngrmr.at/img/oueZ7gnOk0-1024.jpeg 1024w, https://ngrmr.at/img/oueZ7gnOk0-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Women selling flowers in Užice." title="Women selling flowers in Užice." loading="lazy" decoding="async" src="https://ngrmr.at/img/oueZ7gnOk0-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/RoEQpF0NK_-480.avif 480w, https://ngrmr.at/img/RoEQpF0NK_-1024.avif 1024w, https://ngrmr.at/img/RoEQpF0NK_-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/RoEQpF0NK_-480.jpeg 480w, https://ngrmr.at/img/RoEQpF0NK_-1024.jpeg 1024w, https://ngrmr.at/img/RoEQpF0NK_-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Panorama picture of Užice." title="Panorama picture of Užice." loading="lazy" decoding="async" src="https://ngrmr.at/img/RoEQpF0NK_-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/PmWI1lvlvt-480.avif 480w, https://ngrmr.at/img/PmWI1lvlvt-1024.avif 1024w, https://ngrmr.at/img/PmWI1lvlvt-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/PmWI1lvlvt-480.jpeg 480w, https://ngrmr.at/img/PmWI1lvlvt-1024.jpeg 1024w, https://ngrmr.at/img/PmWI1lvlvt-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Landscape near Zlatibor." title="Landscape near Zlatibor." loading="lazy" decoding="async" src="https://ngrmr.at/img/PmWI1lvlvt-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/VCByAX0BQ6-480.avif 480w, https://ngrmr.at/img/VCByAX0BQ6-1024.avif 1024w, https://ngrmr.at/img/VCByAX0BQ6-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/VCByAX0BQ6-480.jpeg 480w, https://ngrmr.at/img/VCByAX0BQ6-1024.jpeg 1024w, https://ngrmr.at/img/VCByAX0BQ6-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="The skyline of Zlatibor. Highrise hotels, some still under construction, in the middle of a serene landscape." title="The skyline of Zlatibor. Highrise hotels, some still under construction, in the middle of a serene landscape." loading="lazy" decoding="async" src="https://ngrmr.at/img/VCByAX0BQ6-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/HVAuZ-oa2q-480.avif 480w, https://ngrmr.at/img/HVAuZ-oa2q-1024.avif 1024w, https://ngrmr.at/img/HVAuZ-oa2q-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/HVAuZ-oa2q-480.jpeg 480w, https://ngrmr.at/img/HVAuZ-oa2q-1024.jpeg 1024w, https://ngrmr.at/img/HVAuZ-oa2q-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Mountains and the sun bursting through thick clouds." title="Mountains and the sun bursting through thick clouds." loading="lazy" decoding="async" src="https://ngrmr.at/img/HVAuZ-oa2q-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/WniW4RoEM9-480.avif 480w, https://ngrmr.at/img/WniW4RoEM9-1024.avif 1024w, https://ngrmr.at/img/WniW4RoEM9-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/WniW4RoEM9-480.jpeg 480w, https://ngrmr.at/img/WniW4RoEM9-1024.jpeg 1024w, https://ngrmr.at/img/WniW4RoEM9-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Fog lingering in a valley near Nova Varoš." title="Fog lingering in a valley near Nova Varoš." loading="lazy" decoding="async" src="https://ngrmr.at/img/WniW4RoEM9-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/pr_P3-fKd1-480.avif 480w, https://ngrmr.at/img/pr_P3-fKd1-1024.avif 1024w, https://ngrmr.at/img/pr_P3-fKd1-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/pr_P3-fKd1-480.jpeg 480w, https://ngrmr.at/img/pr_P3-fKd1-1024.jpeg 1024w, https://ngrmr.at/img/pr_P3-fKd1-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Washed out gravel road in a misty forest." title="Washed out gravel road in a misty forest." loading="lazy" decoding="async" src="https://ngrmr.at/img/pr_P3-fKd1-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/1D9AFI9Ygx-480.avif 480w, https://ngrmr.at/img/1D9AFI9Ygx-1024.avif 1024w, https://ngrmr.at/img/1D9AFI9Ygx-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/1D9AFI9Ygx-480.jpeg 480w, https://ngrmr.at/img/1D9AFI9Ygx-1024.jpeg 1024w, https://ngrmr.at/img/1D9AFI9Ygx-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Roadside covered with hailstones." title="Roadside covered with hailstones." loading="lazy" decoding="async" src="https://ngrmr.at/img/1D9AFI9Ygx-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/f5TT1KR1n2-480.avif 480w, https://ngrmr.at/img/f5TT1KR1n2-1024.avif 1024w, https://ngrmr.at/img/f5TT1KR1n2-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/f5TT1KR1n2-480.jpeg 480w, https://ngrmr.at/img/f5TT1KR1n2-1024.jpeg 1024w, https://ngrmr.at/img/f5TT1KR1n2-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Valley near Berane." title="Valley near Berane." loading="lazy" decoding="async" src="https://ngrmr.at/img/f5TT1KR1n2-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/eq40GjSdHU-480.avif 480w, https://ngrmr.at/img/eq40GjSdHU-1024.avif 1024w, https://ngrmr.at/img/eq40GjSdHU-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/eq40GjSdHU-480.jpeg 480w, https://ngrmr.at/img/eq40GjSdHU-1024.jpeg 1024w, https://ngrmr.at/img/eq40GjSdHU-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="2 construction workers replacing wood beams on a bridge in the albanian mountains." title="2 construction workers replacing wood beams on a bridge in the albanian mountains." loading="lazy" decoding="async" src="https://ngrmr.at/img/eq40GjSdHU-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/bg2iayAWTN-480.avif 480w, https://ngrmr.at/img/bg2iayAWTN-1024.avif 1024w, https://ngrmr.at/img/bg2iayAWTN-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/bg2iayAWTN-480.jpeg 480w, https://ngrmr.at/img/bg2iayAWTN-1024.jpeg 1024w, https://ngrmr.at/img/bg2iayAWTN-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="My bike at the roadside on my descent down the Cemi valley to Tamarë." title="My bike at the roadside on my descent down the Cemi valley to Tamarë." loading="lazy" decoding="async" src="https://ngrmr.at/img/bg2iayAWTN-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/44fM8yS_qw-480.avif 480w, https://ngrmr.at/img/44fM8yS_qw-1024.avif 1024w, https://ngrmr.at/img/44fM8yS_qw-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/44fM8yS_qw-480.jpeg 480w, https://ngrmr.at/img/44fM8yS_qw-1024.jpeg 1024w, https://ngrmr.at/img/44fM8yS_qw-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Serpentines in the albanian north." title="Serpentines in the albanian north." loading="lazy" decoding="async" src="https://ngrmr.at/img/44fM8yS_qw-480.jpeg" width="3024" height="4032" /></picture></p>
<p>I stayed a night each at the beaches at Shëngjin, Spille, and Darzez. Then I returned inland to Berat and went through Elbasan to Struga at lake Ohrid in North Makedonia. From there I paid the neighboring lake Prespa a visit and returned to Vienna on sunday, August 28th by an 18 hour bus ride.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/4LGO5ACTSA-480.avif 480w, https://ngrmr.at/img/4LGO5ACTSA-1024.avif 1024w, https://ngrmr.at/img/4LGO5ACTSA-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/4LGO5ACTSA-480.jpeg 480w, https://ngrmr.at/img/4LGO5ACTSA-1024.jpeg 1024w, https://ngrmr.at/img/4LGO5ACTSA-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Pictore of the road. a truck passes a couple that is leading a cow." title="Pictore of the road. a truck passes a couple that is leading a cow." loading="lazy" decoding="async" src="https://ngrmr.at/img/4LGO5ACTSA-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/t3vno6ucdC-480.avif 480w, https://ngrmr.at/img/t3vno6ucdC-1024.avif 1024w, https://ngrmr.at/img/t3vno6ucdC-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/t3vno6ucdC-480.jpeg 480w, https://ngrmr.at/img/t3vno6ucdC-1024.jpeg 1024w, https://ngrmr.at/img/t3vno6ucdC-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Town square of Kavaje. There's cars, palm trees, a mosque, a church tower and a fountain." title="Town square of Kavaje. There's cars, palm trees, a mosque, a church tower and a fountain." loading="lazy" decoding="async" src="https://ngrmr.at/img/t3vno6ucdC-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/sTVNc-PaW8-480.avif 480w, https://ngrmr.at/img/sTVNc-PaW8-1024.avif 1024w, https://ngrmr.at/img/sTVNc-PaW8-6284.avif 6284w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/sTVNc-PaW8-480.jpeg 480w, https://ngrmr.at/img/sTVNc-PaW8-1024.jpeg 1024w, https://ngrmr.at/img/sTVNc-PaW8-6284.jpeg 6284w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Panoramic image of a beach bar in the pine forrest at Spille." title="Panoramic image of a beach bar in the pine forrest at Spille." loading="lazy" decoding="async" src="https://ngrmr.at/img/sTVNc-PaW8-480.jpeg" width="6284" height="1660" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/3dkmT_4GNc-480.avif 480w, https://ngrmr.at/img/3dkmT_4GNc-1024.avif 1024w, https://ngrmr.at/img/3dkmT_4GNc-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/3dkmT_4GNc-480.jpeg 480w, https://ngrmr.at/img/3dkmT_4GNc-1024.jpeg 1024w, https://ngrmr.at/img/3dkmT_4GNc-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Gravel road leading to Spille." title="Gravel road leading to Spille." loading="lazy" decoding="async" src="https://ngrmr.at/img/3dkmT_4GNc-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/gC4RmyUuRc-480.avif 480w, https://ngrmr.at/img/gC4RmyUuRc-1024.avif 1024w, https://ngrmr.at/img/gC4RmyUuRc-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/gC4RmyUuRc-480.jpeg 480w, https://ngrmr.at/img/gC4RmyUuRc-1024.jpeg 1024w, https://ngrmr.at/img/gC4RmyUuRc-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Street market in Gosë" title="Street market in Gosë" loading="lazy" decoding="async" src="https://ngrmr.at/img/gC4RmyUuRc-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/u_3I4h-YaT-480.avif 480w, https://ngrmr.at/img/u_3I4h-YaT-1024.avif 1024w, https://ngrmr.at/img/u_3I4h-YaT-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/u_3I4h-YaT-480.jpeg 480w, https://ngrmr.at/img/u_3I4h-YaT-1024.jpeg 1024w, https://ngrmr.at/img/u_3I4h-YaT-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Bridge with very bad surface." title="Bridge with very bad surface." loading="lazy" decoding="async" src="https://ngrmr.at/img/u_3I4h-YaT-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/x0FZXjIWzC-480.avif 480w, https://ngrmr.at/img/x0FZXjIWzC-1024.avif 1024w, https://ngrmr.at/img/x0FZXjIWzC-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/x0FZXjIWzC-480.jpeg 480w, https://ngrmr.at/img/x0FZXjIWzC-1024.jpeg 1024w, https://ngrmr.at/img/x0FZXjIWzC-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Sandy road at Darzez beach in the Pishë Poro natural reservation area." title="Sandy road at Darzez beach in the Pishë Poro natural reservation area." loading="lazy" decoding="async" src="https://ngrmr.at/img/x0FZXjIWzC-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/NoiwseSRLv-480.avif 480w, https://ngrmr.at/img/NoiwseSRLv-1024.avif 1024w, https://ngrmr.at/img/NoiwseSRLv-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/NoiwseSRLv-480.jpeg 480w, https://ngrmr.at/img/NoiwseSRLv-1024.jpeg 1024w, https://ngrmr.at/img/NoiwseSRLv-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Hut at Darzez beach." title="Hut at Darzez beach." loading="lazy" decoding="async" src="https://ngrmr.at/img/NoiwseSRLv-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/jZEYAeP9z--480.avif 480w, https://ngrmr.at/img/jZEYAeP9z--1024.avif 1024w, https://ngrmr.at/img/jZEYAeP9z--3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/jZEYAeP9z--480.jpeg 480w, https://ngrmr.at/img/jZEYAeP9z--1024.jpeg 1024w, https://ngrmr.at/img/jZEYAeP9z--3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="100% steel bridge." title="100% steel bridge." loading="lazy" decoding="async" src="https://ngrmr.at/img/jZEYAeP9z--480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/N6sDI_qOsu-480.avif 480w, https://ngrmr.at/img/N6sDI_qOsu-1024.avif 1024w, https://ngrmr.at/img/N6sDI_qOsu-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/N6sDI_qOsu-480.jpeg 480w, https://ngrmr.at/img/N6sDI_qOsu-1024.jpeg 1024w, https://ngrmr.at/img/N6sDI_qOsu-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Forrest fires on a hill near Berat." title="Forrest fires on a hill near Berat." loading="lazy" decoding="async" src="https://ngrmr.at/img/N6sDI_qOsu-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/gcOleQfeAs-480.avif 480w, https://ngrmr.at/img/gcOleQfeAs-1024.avif 1024w, https://ngrmr.at/img/gcOleQfeAs-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/gcOleQfeAs-480.jpeg 480w, https://ngrmr.at/img/gcOleQfeAs-1024.jpeg 1024w, https://ngrmr.at/img/gcOleQfeAs-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Railroad bridge." title="Railroad bridge." loading="lazy" decoding="async" src="https://ngrmr.at/img/gcOleQfeAs-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/BU720ht-ML-480.avif 480w, https://ngrmr.at/img/BU720ht-ML-1024.avif 1024w, https://ngrmr.at/img/BU720ht-ML-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/BU720ht-ML-480.jpeg 480w, https://ngrmr.at/img/BU720ht-ML-1024.jpeg 1024w, https://ngrmr.at/img/BU720ht-ML-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Fishing men on a concrete pier at lake Ohrid." title="Fishing men on a concrete pier at lake Ohrid." loading="lazy" decoding="async" src="https://ngrmr.at/img/BU720ht-ML-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/zfi5l0XqKy-480.avif 480w, https://ngrmr.at/img/zfi5l0XqKy-1024.avif 1024w, https://ngrmr.at/img/zfi5l0XqKy-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/zfi5l0XqKy-480.jpeg 480w, https://ngrmr.at/img/zfi5l0XqKy-1024.jpeg 1024w, https://ngrmr.at/img/zfi5l0XqKy-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Cows on the mountain road from lake Ohrid to lake Prespa." title="Cows on the mountain road from lake Ohrid to lake Prespa." loading="lazy" decoding="async" src="https://ngrmr.at/img/zfi5l0XqKy-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/5mKuRxPA7s-480.avif 480w, https://ngrmr.at/img/5mKuRxPA7s-1024.avif 1024w, https://ngrmr.at/img/5mKuRxPA7s-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/5mKuRxPA7s-480.jpeg 480w, https://ngrmr.at/img/5mKuRxPA7s-1024.jpeg 1024w, https://ngrmr.at/img/5mKuRxPA7s-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="My bike getting a proper wash at the end of a demanding journey." title="My bike getting a proper wash at the end of a demanding journey." loading="lazy" decoding="async" src="https://ngrmr.at/img/5mKuRxPA7s-480.jpeg" width="3024" height="4032" /></picture></p>
<h2>Equipment</h2>
<p>I opted for minimal gear for this trip. Only one set of cycling garment, wind- and rain jackets, and one set of civil clothing. I took no camping equipment with me. This allowed me to use only a saddle back, a frame back and a small upper-tube back on my <a href="https://ngrmr.at/cycling/cannondale-topstone/">Cannondale Topstone</a>.</p>
<h2>Stats</h2>
<p>Duration: 13 days cycling + 1 day bus ride<br />
Distance cycled: 1400 km<br />
Altitude gained: 15000 m<br />
Highest temperature recorded by my cycling computer: 43° Celsius<br />
Number of hailstorms: 2</p>
<h2>Tracking</h2>
<p>This <a href="https://www.komoot.de/collection/2215676/-balkan-2023">collection on Komoot</a> contains all planned routes of my trip.</p>
<p>Here's a list of my rides I tracked on Strava:</p>
<ul>
<li><a href="https://www.strava.com/activities/9647544847">Day 1: Ada</a></li>
<li><a href="https://www.strava.com/activities/9652669566">Day 2: Novi Sad</a></li>
<li><a href="https://www.strava.com/activities/9660106825">Day 3: Šabac</a></li>
<li><a href="https://www.strava.com/activities/9667701069">Day 4: Kosjeric</a></li>
<li><a href="https://www.strava.com/activities/9674129279">Day 5: Nova Varoš</a></li>
<li><a href="https://www.strava.com/activities/9680929083">Day 6: Berane</a></li>
<li><a href="https://www.strava.com/activities/9686734222">Day 7: Tamarë</a></li>
<li><a href="https://www.strava.com/activities/9692717463">Day 8: Shëngjin</a></li>
<li><a href="https://www.strava.com/activities/9698048880">Day 9: Spille</a></li>
<li><a href="https://www.strava.com/activities/9706023292">Day 10: Pishë Poro</a></li>
<li><a href="https://www.strava.com/activities/9711097754">Day 11: Berat</a></li>
<li><a href="https://www.strava.com/activities/9717996827">Day 12: Struga</a></li>
<li><a href="https://www.strava.com/activities/9724266899">Day 13: Ohrid and Prespa lakes</a></li>
</ul>
2023 Out of the Alps2023-07-10T00:00:00Zhttps://ngrmr.at/cycling/2023-out-of-the-alps/<h1>2023 Out of the Alps</h1>
<p>After recovering from a fractured collar bone I ventured for my first two day tour after 8 months. After visiting friends in Schwaz, my personal cycling guru Emu and I took the train to St. Johann (Tirol) from where we rode on a gravel road over the Hirschbichl pass to Berchtesgarden and on to Hallein.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/cnmGzeIcpJ-480.avif 480w, https://ngrmr.at/img/cnmGzeIcpJ-1024.avif 1024w, https://ngrmr.at/img/cnmGzeIcpJ-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/cnmGzeIcpJ-480.jpeg 480w, https://ngrmr.at/img/cnmGzeIcpJ-1024.jpeg 1024w, https://ngrmr.at/img/cnmGzeIcpJ-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="A young cow on green mountain meadows behind a fence looking straight into the camera." title="A young cow on green mountain meadows behind a fence looking straight into the camera." loading="lazy" decoding="async" src="https://ngrmr.at/img/cnmGzeIcpJ-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/blHMThUOMd-480.avif 480w, https://ngrmr.at/img/blHMThUOMd-1024.avif 1024w, https://ngrmr.at/img/blHMThUOMd-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/blHMThUOMd-480.jpeg 480w, https://ngrmr.at/img/blHMThUOMd-1024.jpeg 1024w, https://ngrmr.at/img/blHMThUOMd-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Emu rolling over the summit on Hirschbichl pass. Mountains and trees in the background." title="Emu rolling over the summit on Hirschbichl pass. Mountains and trees in the background." loading="lazy" decoding="async" src="https://ngrmr.at/img/blHMThUOMd-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/llXUOorDVw-480.avif 480w, https://ngrmr.at/img/llXUOorDVw-1024.avif 1024w, https://ngrmr.at/img/llXUOorDVw-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/llXUOorDVw-480.jpeg 480w, https://ngrmr.at/img/llXUOorDVw-1024.jpeg 1024w, https://ngrmr.at/img/llXUOorDVw-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Emu crossing a dry ford on the way down from Hirschbichl." title="Emu crossing a dry ford on the way down from Hirschbichl." loading="lazy" decoding="async" src="https://ngrmr.at/img/llXUOorDVw-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/AUoXF01ka7-480.avif 480w, https://ngrmr.at/img/AUoXF01ka7-1024.avif 1024w, https://ngrmr.at/img/AUoXF01ka7-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/AUoXF01ka7-480.jpeg 480w, https://ngrmr.at/img/AUoXF01ka7-1024.jpeg 1024w, https://ngrmr.at/img/AUoXF01ka7-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Scenery at Hintersee, Ramsau." title="Scenery at Hintersee, Ramsau." loading="lazy" decoding="async" src="https://ngrmr.at/img/AUoXF01ka7-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/8j4xv_OD2s-480.avif 480w, https://ngrmr.at/img/8j4xv_OD2s-1024.avif 1024w, https://ngrmr.at/img/8j4xv_OD2s-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/8j4xv_OD2s-480.jpeg 480w, https://ngrmr.at/img/8j4xv_OD2s-1024.jpeg 1024w, https://ngrmr.at/img/8j4xv_OD2s-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Emu at top of the last hill before Hallein. Small road, some scattered houses, green grass and a blue sky." title="Emu at top of the last hill before Hallein. Small road, some scattered houses, green grass and a blue sky." loading="lazy" decoding="async" src="https://ngrmr.at/img/8j4xv_OD2s-480.jpeg" width="4032" height="3024" /></picture></p>
<p>The next day started rainy but eventually it dried up and I continued my journey east over the Postalm — again on a gravel road — from where I descended on a paved road to Bad Ischl and on to Ebensee at the southern shores of lake Traunsee. From there I returned by train to Vienna.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/pSKFVzGEFD-480.avif 480w, https://ngrmr.at/img/pSKFVzGEFD-1024.avif 1024w, https://ngrmr.at/img/pSKFVzGEFD-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/pSKFVzGEFD-480.jpeg 480w, https://ngrmr.at/img/pSKFVzGEFD-1024.jpeg 1024w, https://ngrmr.at/img/pSKFVzGEFD-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Look into a narrow valley on the way up to Postalm." title="Look into a narrow valley on the way up to Postalm." loading="lazy" decoding="async" src="https://ngrmr.at/img/pSKFVzGEFD-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/Mb5MHFdQbI-480.avif 480w, https://ngrmr.at/img/Mb5MHFdQbI-1024.avif 1024w, https://ngrmr.at/img/Mb5MHFdQbI-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/Mb5MHFdQbI-480.jpeg 480w, https://ngrmr.at/img/Mb5MHFdQbI-1024.jpeg 1024w, https://ngrmr.at/img/Mb5MHFdQbI-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Scenery at Postalm: Meadows, two cottages in the distance, some fir trees and a small stream beneath a grey sky." title="Scenery at Postalm: Meadows, two cottages in the distance, some fir trees and a small stream beneath a grey sky." loading="lazy" decoding="async" src="https://ngrmr.at/img/Mb5MHFdQbI-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/JO7vZsQQ9D-480.avif 480w, https://ngrmr.at/img/JO7vZsQQ9D-1024.avif 1024w, https://ngrmr.at/img/JO7vZsQQ9D-3024.avif 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/JO7vZsQQ9D-480.jpeg 480w, https://ngrmr.at/img/JO7vZsQQ9D-1024.jpeg 1024w, https://ngrmr.at/img/JO7vZsQQ9D-3024.jpeg 3024w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="My Cannondale Topstone leaning against the summit sign on Postalm." title="My Cannondale Topstone leaning against the summit sign on Postalm." loading="lazy" decoding="async" src="https://ngrmr.at/img/JO7vZsQQ9D-480.jpeg" width="3024" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/Vlv442YJ6e-480.avif 480w, https://ngrmr.at/img/Vlv442YJ6e-1024.avif 1024w, https://ngrmr.at/img/Vlv442YJ6e-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/Vlv442YJ6e-480.jpeg 480w, https://ngrmr.at/img/Vlv442YJ6e-1024.jpeg 1024w, https://ngrmr.at/img/Vlv442YJ6e-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="The road winding down from Postalm. Light shreds of a cloud hang before the neighboring mountain top." title="The road winding down from Postalm. Light shreds of a cloud hang before the neighboring mountain top." loading="lazy" decoding="async" src="https://ngrmr.at/img/Vlv442YJ6e-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/j1cXyVnDZH-480.avif 480w, https://ngrmr.at/img/j1cXyVnDZH-1024.avif 1024w, https://ngrmr.at/img/j1cXyVnDZH-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/j1cXyVnDZH-480.jpeg 480w, https://ngrmr.at/img/j1cXyVnDZH-1024.jpeg 1024w, https://ngrmr.at/img/j1cXyVnDZH-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Road lined with old trees near Ebenseee." title="Road lined with old trees near Ebenseee." loading="lazy" decoding="async" src="https://ngrmr.at/img/j1cXyVnDZH-480.jpeg" width="4032" height="3024" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/xPFi4FnYy--480.avif 480w, https://ngrmr.at/img/xPFi4FnYy--1024.avif 1024w, https://ngrmr.at/img/xPFi4FnYy--4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/xPFi4FnYy--480.jpeg 480w, https://ngrmr.at/img/xPFi4FnYy--1024.jpeg 1024w, https://ngrmr.at/img/xPFi4FnYy--4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Scenery at Ebensee. A lake surrounded by towering mountains on all sides beneath a lightly clouded sky. There's a quay with concrete springboard, but no people populating it." title="Scenery at Ebensee. A lake surrounded by towering mountains on all sides beneath a lightly clouded sky. There's a quay with concrete springboard, but no people populating it." loading="lazy" decoding="async" src="https://ngrmr.at/img/xPFi4FnYy--480.jpeg" width="4032" height="3024" /></picture></p>
<h2>Stats</h2>
<p>Duration: 2 Days<br />
Distance: ~160 km<br />
Altitude gained: 2100 m<br />
Highest climb: 622 m (Wildental to Hirschbichl)<br />
Highest elevation: 1297 m (Hirschbichl)</p>
<h2>Tracking</h2>
<ul>
<li><a href="https://www.strava.com/activities/9369192072">Day 1 on Strava</a></li>
<li><a href="https://www.strava.com/activities/9374881576">Day 2 on Strava</a></li>
</ul>
Arranging diamond tiles in a grid2023-02-20T22:15:00Zhttps://ngrmr.at/blog/2023-02-20-break-after-even-element/<p>Some weeks ago I added webmentions support to my website - which is coincidentally the site you are browsing right now. To pick up on the diamond shape used in the logo of the site, I wanted the avatars/user images of comments, mentions, and backlinks to be cropped to a diamond shape, i.e. a square rotated by 45 degrees. I already wrote a bit about <a href="https://ngrmr.at/til/2023-01-06-transition-clip-path-polygon/">shaping and animating that shape</a>.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diamonds<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>4<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>5<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">.diamonds</span> <span class="token punctuation">{</span><br /> <span class="token property">--sq</span><span class="token punctuation">:</span> 60px<span class="token punctuation">;</span><br /> <span class="token property">--sq-gap</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span><br /> <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--sq-gap<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.diamonds li</span> <span class="token punctuation">{</span><br /> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span><br /> <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span><br /> <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span><br /> <span class="token property">margin-inline-end</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span><br /> <span class="token property">background</span><span class="token punctuation">:</span> lightsalmon<span class="token punctuation">;</span><br /> <span class="token property">color</span><span class="token punctuation">:</span> slateblue<span class="token punctuation">;</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 50% 0%<span class="token punctuation">,</span><br /> 100% 50%<span class="token punctuation">,</span><br /> 50% 100%<span class="token punctuation">,</span><br /> 0% 50%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /></code></pre>
<div class="example">
<ul class="diamonds">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<style>
.example {
--sq: 60px;
--sq-gap: 4px;
}
.diamonds {
display: flex;
gap: var(--sq-gap);
padding-inline-start: 0;
}
.diamonds li {
background: lightsalmon;
color: slateblue;
width: var(--sq);
height: var(--sq);
display: flex;
align-items: center;
justify-content: center;
clip-path: polygon(
50% 0%,
100% 50%,
50% 100%,
0% 50%
);
}
</style>
<p>When there are multiple images to be displayed next to each other, the diamond shape causes too much white space between the list elements for my taste. I thought it would be neat, to arrange the squares in a tightly packed grid like tiles on a floor. To do this, I set the inline margin of each square -50% of its with, and the block margin of every second square to -50% of its height.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.diamonds.tiled</span> <span class="token punctuation">{</span><br /> <span class="token property">padding-inline-start</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>0.5 * <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">padding-block-start</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>0.5 * <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.diamonds.tiled li</span> <span class="token punctuation">{</span><br /> <span class="token property">margin-inline-start</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>-0.5 * <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.diamonds.tiled li:nth-child(even)</span> <span class="token punctuation">{</span><br /> <span class="token property">margin-block-start</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>-0.5 * <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span> - 0.5 * <span class="token function">var</span><span class="token punctuation">(</span>--sq-gap<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> palegoldenrod<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /></code></pre>
<div class="example">
<ul class="diamonds tiled resizable">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<ul class="diamonds tiled resizable">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
</ul>
</div>
<style>
.diamonds.tiled {
margin-block-start: 0;
padding-inline-start: calc(0.5 * var(--sq));
padding-block-start: calc(0.5 * var(--sq));
}
.diamonds.tiled li {
margin-inline-start: calc(-0.5 * var(--sq));
}
.diamonds.tiled li:nth-child(even) {
margin-block-start: calc(-0.5 * var(--sq) - 0.5 * var(--sq-gap));
background-color: palegoldenrod;
}
</style>
<p>That looks nice, but what for the uncertain but not totally impossible scenario where one of my posts gets shared and liked a dozen times? Depending on the available space, the diamonds would sooner or later get squashed because they are layed out with flexbox. To perform some premature optimization, I allow the items to wrap. For illustrative purposes, let's set the width of the list element to cause a wrap and show a red border.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.diamonds.wrapping</span> <span class="token punctuation">{</span><br /> <span class="token property">flex-wrap</span><span class="token punctuation">:</span> wrap<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /></code></pre>
<div class="example">
<ul class="diamonds tiled wrapping resizable">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
</ul>
</div>
<style>
.diamonds.wrapping {
flex-wrap: wrap;
}
.resizable {
width: calc(4 * var(--sq));
border: 1px dotted red;
resize: horizontal;
overflow: hidden;
}
</style>
<p>Ouch, in cases where the wrap happens after an odd numbered square, elements after the wrap will overlap with preceding ones. How can we make sure to that the wrap happens after an even numbered element? My first instinct was to use an <code>:nth-child(even)</code> CSS selector and some clever properties but this lead to nothing.</p>
<p>What I finally came up with was to wrap the list with a container element which defines a grid layout. The first column of that grid has half the width of one of the squares. It is followed by an auto-repeated number of columns where each has the width of a whole square with a gap matching the margin between two of them. The child list element <code>.diamonds</code> is set to stretch over all columns of this grid. This works because the width of the diamonds is known.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diamond-container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diamonds tiled wrapping<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>etc.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">.diamond-container</span> <span class="token punctuation">{</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span><br /> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>0.5 * <span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">repeat</span><span class="token punctuation">(</span>auto-fill<span class="token punctuation">,</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--sq<span class="token punctuation">)</span> + 2 * <span class="token function">var</span><span class="token punctuation">(</span>--sq-gap<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.diamond-container .diamonds</span> <span class="token punctuation">{</span><br /> <span class="token property">grid-column-start</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br /> <span class="token property">grid-column-end</span><span class="token punctuation">:</span> -1<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example">
<div class="diamond-container resizable">
<ul class="diamonds tiled wrapping">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
</ul>
</div>
</div>
<style>
.diamond-container {
display: grid;
grid-template-columns: calc(0.5 * var(--sq)) repeat(auto-fill, var(--sq));
gap: calc(2 * var(--sq-gap));
}
.diamond-container .diamonds {
grid-column-start: 1;
grid-column-end: -1;
}
</style>
<p>Although I'm not a big fan of adding additional markup in order to achieve some visual effect, I'm quite happy with this solution.<br />
Hopefully you can observe it in full effect below in the Feedback section.</p>
<h2>Addendum, 2023-02-21 9:30</h2>
<p>Similar layouts have been built before but with different approaches:</p>
<p><a href="https://ninjarockstar.dev/css-hex-grids/">Jesse Breneman used a sophisticated grid</a> where he places hexagonal shapes.</p>
<a href="https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/">
Temani Afif uses the `shape-outside` property</a> to create a jagged element and floats various shapes around it.2023-01-06T17:00:53Zhttps://ngrmr.at/<link rel="stylesheet" href="https://ngrmr.at/css/cardboard-box.css" />
<div class="cb">
<main class="cb-box">
<div class="cb-side cb-side--top">
<a href="https://ngrmr.at/" class="cb__home">
<img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" />
<h1 class="visually-hidden">Rupert Angermeier</h1>
</a>
</div>
<div class="cb-side cb-side--front">
<div class="el-stack">
<p>This is the website of <a href="https://ngrmr.at/about">Rupert Angermeier</a>.</p>
<p>Occasionally I manage to write something down. The latest fruits of my writing efforts can be found on my <a href="https://ngrmr.at/blog">blog</a>:</p>
<ul><li>
<a href="https://ngrmr.at/blog/2023-02-20-break-after-even-element/">Arranging diamond tiles in a grid</a>, <span class="text-small">February 20th, 2023
</span></li><li>
<a href="https://ngrmr.at/blog/2023-01-06-transition-clip-path-polygon/">Transitioning a clip-path polygon shape</a>, <span class="text-small">January 6th, 2023
</span></li><li>
<a href="https://ngrmr.at/blog/2022-12-23-button-with-label/">Attaching a label to a button</a>, <span class="text-small">December 23rd, 2022
</span></li></ul>
<p>Once in a decade or so I write a longer technical article. Here <strike>are some</strike><ins>is one</ins> of them:</p>
<ul>
<li><a href="https://medium.com/trayn-engineering/phasing-out-jquery-8bd6fbb2007a">Phasing out jQuery</a>,
<span class="text-small">published in the Trayn Journal on Medium, July 5th, 2018.</span>
</li>
</ul>
<p>I'm also a <a href="https://ngrmr.at/cycling">cycling person</a>.</p>
</div>
</div>
<div class="cb-side cb-side--back">
<span aria-hidden="true" class="no-print cb__home"><img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" /></span>
</div>
<div class="cb-side cb-side--left">
<span aria-hidden="true" class="no-print cb__home"><img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" /></span>
</div>
<div class="cb-side cb-side--right">
<span aria-hidden="true" class="no-print cb__home"><img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" /></span>
</div>
<div class="cb-side cb-side--bottom">
<footer class="cb__bottom">
<div class="cb__bottom-text">
<a href="https://ngrmr.at/about">Contact & Imprint</a>
<a href="https://ngrmr.at/feed.rss" rel="alternate" type="application/rss+xml">RSS</a>
<a rel="me" href="https://mastodon.social/@rangermeier">Mastodon</a><br />
<abbr title="Manufacturing Date (last built)">MFD</abbr>
<time datetime="2023-09-07">2023-09-07</time><br />
Best before: Always fresh<br />
</div>
<div class="cb__bottom-barcode" aria-hidden="true">
<img src="https://ngrmr.at/assets/barcode.svg" alt="Barcode which decodes to ngrmr.at" />
</div>
</footer>
</div>
</main>
<div class="cb__controls no-print">
<button class="cb__toggle hidden">Fold Box</button>
<button class="cb__rotate hidden">Rotate</button>
</div>
</div>
<script>
(function() {
var cbBox = document.querySelector('.cb-box')
var btnToggle = document.querySelector('.cb__toggle')
var btnRotate = document.querySelector('.cb__rotate')
if(!cbBox || !btnToggle) {
return
}
btnToggle.classList.remove('hidden')
btnToggle.addEventListener('click', function() {
cbBox.classList.toggle('cb-box--folded')
var isFolded = cbBox.classList.contains('cb-box--folded')
cbBox.classList.toggle('cb-box--unfolded', !isFolded)
btnToggle.innerHTML = isFolded ? 'Unfold Box' : 'Fold Box'
btnRotate.classList.toggle('hidden', !isFolded)
btnRotate.innerHTML = 'Rotate'
if(isFolded) {
window.scrollTo(0, 0)
} else {
cbBox.classList.toggle('cb-box--rotating', false)
cbBox.classList.toggle('cb-box--rotate-pause', false)
}
})
btnRotate.addEventListener('click', function() {
var isRotating = cbBox.classList.contains('cb-box--rotating')
if(isRotating) {
cbBox.classList.toggle('cb-box--rotate-pause')
} else {
cbBox.classList.toggle('cb-box--rotating')
}
btnRotate.innerHTML = isRotating ? 'Rotate' : 'Pause'
})
}())
</script>Transitioning a clip-path polygon shape2023-01-06T17:00:00Zhttps://ngrmr.at/blog/2023-01-06-transition-clip-path-polygon/<p>I was building a layout where I wanted to show links with images that are cropped to a diamond shape. When the user points their mouse at the link the shape should change to an octagon.</p>
<p>This can be achieved in CSS by using <a href="https://ngrmr.at/til/2020-01-17-css-color-svg-mask/">SVG masks</a> or by defining a polygon <code>clip-path</code>. Because I wanted to animate the change of the shape, I opted for the <code>clip-path</code>.</p>
<p>When the link is focused through keyboard navigation, I un-set the <code>clip-path</code> because otherwise the focus outline would become invisible as it is also clipped.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>...<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>shaped<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>kitten.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>A cute kitten<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">.shaped</span> <span class="token punctuation">{</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 50% 0%<span class="token punctuation">,</span><br /> 100% 50%<span class="token punctuation">,</span><br /> 50% 100%<span class="token punctuation">,</span><br /> 0% 50%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.shaped:hover</span> <span class="token punctuation">{</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 25% 0%<span class="token punctuation">,</span><br /> 75% 0%<span class="token punctuation">,</span><br /> 100% 25%<span class="token punctuation">,</span><br /> 100% 75%<span class="token punctuation">,</span><br /> 75% 100%<span class="token punctuation">,</span><br /> 25% 100%<span class="token punctuation">,</span><br /> 0% 75%<span class="token punctuation">,</span><br /> 0% 25%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">prefers-reduced-motion</span><span class="token punctuation">:</span> no-preference<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.shaped</span> <span class="token punctuation">{</span><br /> <span class="token property">transition</span><span class="token punctuation">:</span> clip-path 1s<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.shaped:focus-visible</span> <span class="token punctuation">{</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example">
<a href="javascript:void" class="shaped"><img src="https://ngrmr.at/blog/img/kitten.jpg" alt="A cute kitten" /></a>
Move your mouse over the image to change its shape.
</div>
<style>
.shaped {
line-height: 1;
display: inline-block;
clip-path: polygon(
50% 0%,
100% 50%,
50% 100%,
0% 50%
);
}
@media screen and (prefers-reduced-motion: no-preference) {
.shaped {
transition: clip-path 1s;
}
}
.shaped img {
width: 128px;
height: 128px;
}
.shaped:hover {
border: none;
clip-path: polygon(
25% 0%,
75% 0%,
100% 25%,
100% 75%,
75% 100%,
25% 100%,
0% 75%,
0% 25%
);
}
.shaped:focus-visible {
clip-path: none;
}
</style>
<p>You will notice that the transition is not working. This is because the number of vertices in the two polygons don't match up. Vertices are the value pairs that are used for drawing the polygon shape. So in order to get this working we have to make sure the <strong>two polygons</strong> which should be transitioned <strong>have the same number of vertices</strong>. In this example we can repeat each of the vertices in the initial polygon so that the four corners of the diamond are defined by two identical coordinates:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.shaped</span> <span class="token punctuation">{</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 50% 0%<span class="token punctuation">,</span><br /> 50% 0%<span class="token punctuation">,</span><br /> 100% 50%<span class="token punctuation">,</span><br /> 100% 50%<span class="token punctuation">,</span><br /> 50% 100%<span class="token punctuation">,</span><br /> 50% 100%<span class="token punctuation">,</span><br /> 0% 50%<br /> 0% 50%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.shaped:hover</span> <span class="token punctuation">{</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 25% 0%<span class="token punctuation">,</span><br /> 75% 0%<span class="token punctuation">,</span><br /> 100% 25%<span class="token punctuation">,</span><br /> 100% 75%<span class="token punctuation">,</span><br /> 75% 100%<span class="token punctuation">,</span><br /> 25% 100%<span class="token punctuation">,</span><br /> 0% 75%<span class="token punctuation">,</span><br /> 0% 25%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example">
<a href="javascript:void" class="shaped working"><img src="https://ngrmr.at/blog/img/kitten.jpg" alt="A cute kitten" /></a>
Move your mouse over the image to change its shape — smoothly.
</div>
<style>
.working {
clip-path: polygon(
50% 0%,
50% 0%,
100% 50%,
100% 50%,
50% 100%,
50% 100%,
0% 50%,
0% 50%
);
}
</style>
<p>For the two simple shapes in this example one might also use a custom property and some calculations to avoid repetitve code.<br />
That way it also becomes impossible to get a mismatch of vertices between the neutral and the hover state.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.shaped</span> <span class="token punctuation">{</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span><br /> <span class="token property">--clip-offset</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span> 0%<span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>100% - <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span><span class="token punctuation">)</span> 0%<span class="token punctuation">,</span><br /> 100% <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> 100% <span class="token function">calc</span><span class="token punctuation">(</span>100% - <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>100% - <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span><span class="token punctuation">)</span> 100%<span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span> 100%<span class="token punctuation">,</span><br /> 0% <span class="token function">calc</span><span class="token punctuation">(</span>100% - <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> 0% <span class="token function">var</span><span class="token punctuation">(</span>--clip-offset<span class="token punctuation">)</span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.shaped:hover</span> <span class="token punctuation">{</span><br /> <span class="token property">--clip-offset</span><span class="token punctuation">:</span> 25%<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">prefers-reduced-motion</span><span class="token punctuation">:</span> no-preference<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.shaped</span> <span class="token punctuation">{</span><br /> <span class="token property">transition</span><span class="token punctuation">:</span> clip-path 1s<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.shaped:focus-visible</span> <span class="token punctuation">{</span><br /> <span class="token property">clip-path</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example">
<a href="javascript:void" class="shaped final"><img src="https://ngrmr.at/blog/img/kitten.jpg" alt="A cute kitten" title="Purrrrr" /></a>
Move your mouse over the image to make the kitten purr.
</div>
<style>
.final {
--clip-offset: 50%;
clip-path: polygon(
var(--clip-offset) 0%,
calc(100% - var(--clip-offset)) 0%,
100% var(--clip-offset),
100% calc(100% - var(--clip-offset)),
calc(100% - var(--clip-offset)) 100%,
var(--clip-offset) 100%,
0% calc(100% - var(--clip-offset)),
0% var(--clip-offset)
);
}
.final:hover {
--clip-offset: 25%;
}
</style>
<p>Kitten image courtesy of <a href="https://www.flickr.com/photos/17251154@N00/11574648064">Sy</a>, licensed under CC BY-NC-SA 2.0.</p>
Blog2023-01-06T16:45:11Zhttps://ngrmr.at/blog/
<div class="el-stack">
<h1>Blog</h1>
<p>
This page contains a list of small tidbits I discovered and thought interesting enough to write about.
Most articles describe small programming related issues I stumbled upon.
</p>
<ol reversed=""><li>
<a href="https://ngrmr.at/blog/2023-02-20-break-after-even-element/">Arranging diamond tiles in a grid</a>, <span class="text-small">February 20th, 2023</span><p>How to cause a list of items to wrap at the right position.</p>
</li><li>
<a href="https://ngrmr.at/blog/2023-01-06-transition-clip-path-polygon/">Transitioning a clip-path polygon shape</a>, <span class="text-small">January 6th, 2023</span><p>When animating the clip-path for an element, the number of vertices have to match.</p>
</li><li>
<a href="https://ngrmr.at/blog/2022-12-23-button-with-label/">Attaching a label to a button</a>, <span class="text-small">December 23rd, 2022</span><p>The label element may be used for buttons too.</p>
</li><li>
<a href="https://ngrmr.at/blog/2022-12-17-circular-translate/">Move an element along a circle segment</a>, <span class="text-small">December 17th, 2022</span><p>How to move an HTML element along a circular segment path with CSS.</p>
</li><li>
<a href="https://ngrmr.at/blog/2022-12-14-position-legend-inside-fieldset/">Placing a fieldset's legend within the border</a>, <span class="text-small">December 14th, 2022</span><p>How to overcome the default placement of a legend element on the fieldset's top border.</p>
</li><li>
<a href="https://ngrmr.at/blog/2022-02-18-svg-foreignobject/">Embed HTML in SVG</a>, <span class="text-small">February 18th, 2022</span>
</li><li>
<a href="https://ngrmr.at/blog/2022-02-09-background-clip/">Transparent borders for tables</a>, <span class="text-small">February 9th, 2022</span>
</li><li>
<a href="https://ngrmr.at/blog/2021-12-09-any-pointer/">Media queries with any-pointer</a>, <span class="text-small">December 14th, 2021</span>
</li><li>
<a href="https://ngrmr.at/blog/2021-12-09-get-event-listeners/">Find event listeners for DOM element</a>, <span class="text-small">December 9th, 2021</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-12-17-nesting-promises/">Nesting Promises</a>, <span class="text-small">December 17th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-05-08-clearinterval-cleartimeout/">clearInterval and clearTimeout are interchangeable</a>, <span class="text-small">May 8th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-04-07-window-devicepxelratio/">Detect Browser Zoom</a>, <span class="text-small">April 7th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-02-15-css-gradient-double-position/">CSS Gradient double position syntax</a>, <span class="text-small">February 15th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-01-19-pause-css-animation/">Pause a CSS animation</a>, <span class="text-small">January 19th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-01-17-css-color-svg-mask/">Color SVGs with a CSS mask</a>, <span class="text-small">January 17th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2020-01-14-spread-css-custom-properties/">CSS custom properties don't have to be valid CSS properties</a>, <span class="text-small">January 14th, 2020</span>
</li><li>
<a href="https://ngrmr.at/blog/2019-11-12-nginx-upload-maxsize/">Nginx default upload size</a>, <span class="text-small">November 12th, 2019</span>
</li></ol>
</div>Attaching a label to a button2022-12-23T13:30:00Zhttps://ngrmr.at/blog/2022-12-23-button-with-label/<p>The <code><label></code> element is used to put a caption on interactive elements like <code><input></code>, <code><textarea></code>, <code><select></code>, <code><meter></code>, etc. Those elements would otherwise have semantically no name, so for good usability and accessability it's mandatory to use the <code><label></code> element or one of the <code>aria-label</code>/<code>aria-labelledby</code> attributes. Clicking the label will activate the labeled control.</p>
<p>However, it's also valid HTML to use the <code><label></code> together with a <code><button></code> element, or an <code><input type="button"></code>. Clicking the label will cause a click event on the button. However, be aware that this may cause some issues with assistive technologies, as the button will now have a label that diverges from its inner text.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>This is the label - try clicking it<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span><br /> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-button<span class="token punctuation">"</span></span><br /> <span class="token special-attr"><span class="token attr-name">onClick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript">window<span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Clickety Clack'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span><br /> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span><br /><span class="token punctuation">></span></span>How about a button<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span></code></pre>
<div class="example">
<label for="my-button">This is the label, try clicking it</label>
<button id="my-button" onClick="window.alert('Clickety Clack')" type="button">How about a button</button>
</div>
Move an element along a circle segment2022-12-17T17:10:52Zhttps://ngrmr.at/blog/2022-12-17-circular-translate/<style>
.example {
overflow: hidden;
--radius: 200px;
}
.hint {
font-size: 0.8rem;
color: #555;
background-color: #f4f4f4;
}
.area {
height: calc(var(--radius) * 1.25);
position: relative;
}
.area::after {
content: "";
display: block;
position: absolute;
top: 0px;
left: calc(var(--radius) * -1);
border: 1px solid green;
border-radius: var(--radius);
width: calc(var(--radius) * 2);
height: calc(var(--radius) * 2);
z-index: 0;
}
.element {
width: 20px;
height: 20px;
border: 1px solid blue;
transition: translate 1s linear;
}
.start, .target, .marker {
width: 1px;
height: 1px;
outline: 2px solid red;
outline-offset: 2px;
border-radius: 2px;
position: absolute;
}
.start {
top: 0px;
left: 0px;
}
.target {
top: var(--radius);
left: var(--radius);
}
.marker {
outline: 1px solid purple;
font-size: 0.7rem;
}
</style>
<h2>Motivation</h2>
<p>I was trying to make an element appear to move along a circular path. I needed this for the <em>folding</em> animation of the backside of the box on my website's <a href="https://ngrmr.at/">start</a> page.</p>
<h2>Problem</h2>
<p>We can use the <code>translate</code> property to change the position of the element. In this example, hovering the parent element moves the element vertically and horizontally by 100px. The element will move along a straight line from point 1 to point 2. The goal is to make the element with the blue border follow the green circle segment.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.element</span> <span class="token punctuation">{</span><br /> <span class="token property">transition</span><span class="token punctuation">:</span> translate 1s linear<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.area:hover .element</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 100px 100px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example example-1">
<div class="area">
<div class="start">1</div>
<div class="target">2</div>
<div class="element"></div>
</div>
<em class="hint">Move your cursor over the grey area or tap on it to initiate the animation.</em>
</div>
<style>
.example-1 .area:hover .element {
translate: var(--radius) var(--radius);
}
</style>
<h2>Approach 1: Animation with pre-calculated positions</h2>
<p>We can use a <code>@keyframe</code> animation to define some points the element should follow along when moving. The element will only follow approximately along the green circle because it still moves in a straight line from one defined point to the next.</p>
<p>If your trigonometry is as rusty as mine: To calculate the <em>x</em> coordinate we use the sinus, i.e. with JavaScript <code>Math.sin(segment_size * 2 * Math.PI * keyframe_progress) * total_translate</code>, where <code>segement_size</code> is the fraction of the circle we want to move along (i.e. for the quarter circle in this example it is 0.25), keyframe_progress is the <code>percentage</code> of the keyframe (i.e. 0.33) and <code>total_translate</code> is the final translated position (i.e. 100).<br />
For the <em>y</em> coordinate we use the cosinus, i.e. w <code>(1 - Math.cos(segment_size * 2 * Math.PI * keyframe_progress)) * total_translate</code></p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> approx-circular-path</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 0px 0px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">33%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 49.54px 13.13px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">66%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 86.07px 49.09px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 100px 100px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.area:hover .element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> 1s linear forward approx-circular-path<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example example-2">
<div class="area">
<div class="start">1</div>
<div class="target">2</div>
<div class="marker marker-33">33%</div>
<div class="marker marker-66">66%</div>
<div class="element"></div>
</div>
</div>
<style>
@keyframes approx-circular-path {
0% {
translate: 0px 0px;
}
33% {
translate: calc(var(--radius) * .4954) calc(var(--radius) * 0.1313);
}
66% {
translate: calc(var(--radius) * .8607) calc(var(--radius) * .4909);
}
100% {
translate: var(--radius) var(--radius);
}
}
.example-2 .marker-33 {
translate: calc(var(--radius) * .4954) calc(var(--radius) * 0.1313);
}
.example-2 .marker-66 {
translate: calc(var(--radius) * .8607) calc(var(--radius) * .4909);
}
.example-2 .element {
animation: 3s linear forwards infinite approx-circular-path;
}
</style>
<p>Depending on how fast the animation runs, the distance the element should move and how many keyframes are pre-calculated the result may be more or less satisfying. In this example I calculated only two intermediate keyframes at 33% and 66% of the animation duration (their position is shown as circles on the arc), so the deviation from the desired path is easier to observe.</p>
<h2>Approach 2: Animation with positions calculated with CSS</h2>
<p>Instead of pre-calculating the values, we could use <a href="https://w3c.github.io/csswg-drafts/css-values/#trig-funcs">CSS trigonometry functions</a>. At point of writing these functions are supported in Firefox and Safari. We still have to define a sufficient number of keyframes in order to get a smooth animation.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.area</span> <span class="token punctuation">{</span><br /> <span class="token property">--radius</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> approx-circular-path</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 0px 0px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">33%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span> * <span class="token function">sin</span><span class="token punctuation">(</span>0.33 * 90deg<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span> * <span class="token punctuation">(</span>1 - <span class="token function">cos</span><span class="token punctuation">(</span>0.33 * 90deg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">66%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span> * <span class="token function">sin</span><span class="token punctuation">(</span>0.66 * 90deg<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span> * <span class="token punctuation">(</span>1 - <span class="token function">cos</span><span class="token punctuation">(</span>0.66 * 90deg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.area:hover .element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> 1s linear forwards trigonometry-circular-path<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example example-3">
<strong class="no-trigonometry-functions">
Your browser doesn't support CSS trigonometry functions. This animation will not work as intended.
</strong>
<div class="area">
<div class="start">1</div>
<div class="target">2</div>
<div class="marker marker-33">33%</div>
<div class="marker marker-66">66%</div>
<div class="element"></div>
</div>
</div>
<style>
@keyframes trigonometry-circular-path {
0% {
translate: 0px 0px;
}
33% {
translate: calc(var(--radius) * sin(0.33 * 90deg)) calc(var(--radius) * (1 - cos(0.33 * 90deg)));
}
66% {
translate: calc(var(--radius) * sin(0.66 * 90deg)) calc(var(--radius) * (1 - cos(0.66 * 90deg)));
}
100% {
translate: var(--radius) var(--radius);
}
}
.example-3 .marker-33 {
translate: calc(var(--radius) * sin(0.33 * 90deg)) calc(var(--radius) * (1 - cos(0.33 * 90deg)));
}
.example-3 .marker-66 {
translate: calc(var(--radius) * sin(0.66 * 90deg)) calc(var(--radius) * (1 - cos(0.66 * 90deg)));
}
.example-3 .element {
animation: 3s linear forwards infinite trigonometry-circular-path;
}
@supports (rotate: calc(sin(1deg) * 1deg)) {
.no-trigonometry-functions {
display: none;
}
}
</style>
<p>If your browser supports trigonometry functions in CSS, the result will be identical to that from <em>Approach 1</em></p>
<h2>Approach 3: Combine animations with timing functions</h2>
<p>In the two previous shown approaches I used the <code>linear</code> timing functions for the animations. We want to keep that, i.e. the element should not ease in or out. But if we look at the movement along x- and y-axis separately, the speed on each axis is not linear. We can define one animation with fitting <code>animation-timing-function: cubic-bezier(..)</code> for the x-axis, and a second one for the y-axis and then combine them with the <code>animation-composition: add</code> property.</p>
<p>Please be aware that <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition"><code>animation-composition</code></a> is still an experimental technology. It is supported in Safari since version 16 and in Firefox since version 104 behind a feature flag.</p>
<p>The big challenge here is to find cubic bezier functions that closely describe our circle segment. After skimming through an <a href="https://spencermortensen.com/articles/bezier-circle/">article on the subject</a>, not understanding any of it and a bit of <a href="https://cubic-bezier.com/">experimentation</a>, I ended with these parameters for the x-axis <code>cubic-bezier(0.11, .4, .6, .89)</code> and the inverse <code>cubic-bezier(.4, 0.11, .89, .6)</code> for the y-axis.</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> composition-circular-path-x</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 0px 0px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span> 0px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> composition-circular-path-y</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 0px 0px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 0px <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> 1s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span>0.11<span class="token punctuation">,</span> .4<span class="token punctuation">,</span> .6<span class="token punctuation">,</span> .89<span class="token punctuation">)</span> forwards composition-circular-path-x<span class="token punctuation">,</span><br /> 1s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span>.4<span class="token punctuation">,</span> 0.11<span class="token punctuation">,</span> .89<span class="token punctuation">,</span> .6<span class="token punctuation">)</span> forwards composition-circular-path-y<span class="token punctuation">;</span><br /> <span class="token property">animation-composition</span><span class="token punctuation">:</span> add<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example example-4">
<strong class="no-animation-composition">
Your browser doesn't support animation composition.
This animation will not work as intended.
</strong>
<div class="area">
<div class="start">1</div>
<div class="target">2</div>
<div class="element"></div>
</div>
</div>
<style>
@keyframes composition-circular-path-x {
0% {
translate: 0px 0px;
}
100% {
translate: var(--radius) 0px;
}
}
@keyframes composition-circular-path-y {
0% {
translate: 0px 0px;
}
100% {
translate: 0px var(--radius);
}
}
.example-4 .element {
animation: 3s cubic-bezier(0.11, .4, .6, .89) forwards infinite composition-circular-path-x,
3s cubic-bezier(.4, 0.11, .89, .6) forwards infinite composition-circular-path-y;
animation-composition: add;
}
@supports (animation-composition: add) {
.no-animation-composition {
display: none;
}
}
</style>
<p>The resulting movement of the element is not perfectly linear — it's a bit faster in the beginning and then slows down — but the element follows nicely along the green path.</p>
<h2>Conclusion</h2>
<p>So, which of the 3 approaches detailed above should be preferred?<br />
<del>Considering the still poor support for CSS trigonometry functions and the <code>animation-composition</code> property I would recommend for now to use approach 1 as default and wrapped in an <code>@supports</code> rule as an progressive enhancement approach 3:</del> <ins>See Update below.</ins></p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> approx-circular-path</span> <span class="token punctuation">{</span> <span class="token comment">/* see above */</span> <span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> composition-circular-path-x</span> <span class="token punctuation">{</span> <span class="token comment">/* see above */</span> <span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> composition-circular-path-y</span> <span class="token punctuation">{</span> <span class="token comment">/* see above */</span> <span class="token punctuation">}</span><br /><br /><span class="token selector">.area:hover .element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> 1s linear forward approx-circular-path<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@supports</span> <span class="token punctuation">(</span><span class="token property">animation-composition</span><span class="token punctuation">:</span> add<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">.area:hover .element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> 1s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span>0.11<span class="token punctuation">,</span> .4<span class="token punctuation">,</span> .6<span class="token punctuation">,</span> .89<span class="token punctuation">)</span> forwards composition-circular-path-x<span class="token punctuation">,</span><br /> 1s <span class="token function">cubic-bezier</span><span class="token punctuation">(</span>.4<span class="token punctuation">,</span> 0.11<span class="token punctuation">,</span> .89<span class="token punctuation">,</span> .6<span class="token punctuation">)</span> forwards composition-circular-path-y<span class="token punctuation">;</span><br /> <span class="token property">animation-composition</span><span class="token punctuation">:</span> add<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /><span class="token punctuation">}</span></code></pre>
<p>I focused here only on HTML and CSS. Using SVG or JavaScript you could probably find other solutions. Please <a href="https://ngrmr.at/about">let me know</a> if you have any additional ideas, feedback or improvements!</p>
<h2>Update, 2022-12-17 22:20</h2>
<p><a href="https://mastodon.social/@anatudor/109530797564184340">Ana Tudor pointed out on Mastodon</a> how to properly do this by chaining transform operations. She suggests to first rotate and then translate the element. To make this animation match those from my previous examples, I rotate the element back after translating. Thanks Ana!</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> circular-rotate</span> <span class="token punctuation">{</span><br /> <span class="token selector">from</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span><br /> <span class="token function">rotate</span><span class="token punctuation">(</span>-90deg<span class="token punctuation">)</span><br /> <span class="token function">translate</span><span class="token punctuation">(</span>100px<span class="token punctuation">)</span><br /> <span class="token function">rotate</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">to</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span><br /> <span class="token function">rotate</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span><br /> <span class="token function">translate</span><span class="token punctuation">(</span>100px<span class="token punctuation">)</span><br /> <span class="token function">rotate</span><span class="token punctuation">(</span>-90deg<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> 2s linear infinite circular-rotate<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example example-5">
<div class="area">
<div class="start">1</div>
<div class="target">2</div>
<div class="element"></div>
</div>
</div>
<style>
@keyframes circular-rotate {
from {
transform:
rotate(var(--start-ang))
translate(var(--radius))
rotate(calc(-1 * var(--start-ang)));
}
to {
transform:
rotate(var(--end-ang))
translate(var(--radius))
rotate(calc(-1 * var(--end-ang)));
}
}
.example-5 .element {
--start-ang: -90deg;
--end-ang: 0deg;
position: absolute;
top: var(--radius);
animation: 2s linear infinite circular-rotate;
}
</style>
Placing a fieldset's legend within the border2022-12-14T00:00:00Zhttps://ngrmr.at/blog/2022-12-14-position-legend-inside-fieldset/<style>
legend {
background-color: hotpink;
}
</style>
<h2>Motivation</h2>
<p>I was trying to implement a layout where the <code><legend></code> was positioned within the border of its parent <code><fieldset></code>.</p>
<h2>Problem</h2>
<p>By default browsers will place the <code><legend></code> element on top of the <code><fieldset></code> block-start (i.e. top) border.</p>
<p>Here's a basic example of the markup for a fieldset with a legend and a single checkbox:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>fieldset</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>legend</span><span class="token punctuation">></span></span>The Legend<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>legend</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Option 1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>fieldset</span><span class="token punctuation">></span></span></code></pre>
<p>This will be rendered as below. The background color of the legend is set to pink to for illustrative purpose.</p>
<div class="example">
<fieldset>
<legend>The Legend</legend>
<label><input type="checkbox" />Option 1</label>
</fieldset>
</div>
<p>Current versions of Firefox and Google Chrome (107 and 108) don't expose the mechanism for this in their user-agent style sheets. I.e. there's no negative <code>margin-top</code> on the <code><legend></code>, as I would have expected. This behavior appears to be hard wired into browsers and is also explicitly described in the <a href="https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements">HTML spec</a>.</p>
<h2>Solution</h2>
<p>The trick is to set <code>float: left</code> on the <code><legend></code> element. This will cause the <code><legend></code> to be rendered like it was an inline element without any allures.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">legend</span> <span class="token punctuation">{</span><br /> <span class="token property">float</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example">
<fieldset>
<legend style="float: left;">The Legend</legend>
<label><input type="checkbox" />Option 1</label>
</fieldset>
</div>
<p>If the <code><legend></code> shouldn't be shown inline, one might either set its next sibling to display as block element or use a flex layout for the entire fieldset:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">fieldset</span> <span class="token punctuation">{</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span><br /> <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">legend</span> <span class="token punctuation">{</span><br /> <span class="token property">float</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<div class="example">
<fieldset style="display: flex; flex-direction: column;">
<legend style="float: left;">The Legend</legend>
<label><input type="checkbox" />Option 1</label>
</fieldset>
</div>Embed HTML in SVG2022-02-18T00:00:00Zhttps://ngrmr.at/blog/2022-02-18-svg-foreignobject/<p>Placing text in a SVG can be somewhat cumbersome. Styling that text, handling line wraps, etc. even more.<br />
Today I found out, that it's possible to embed HTML into a SVG with the <code><foreignObject></code> element:</p>
<pre class="language-svg"><code class="language-svg"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>svg</span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 200 100<span class="token punctuation">"</span></span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css"><br /> <span class="token selector">.svg-embed</span> <span class="token punctuation">{</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> #ffe<span class="token punctuation">;</span><br /> <span class="token property">font-size</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>rect</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>180<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>80<span class="token punctuation">"</span></span> <span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hotpink<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#ccc<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>text</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>30<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>How boring, text within a text-element<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>text</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>foreignObject</span> <span class="token attr-name">x</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>40<span class="token punctuation">"</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>160<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>60<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>svg-embed<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br /> Some styled <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span>text<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span> with background and <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>a link<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>.<br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>foreignObject</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>svg</span><span class="token punctuation">></span></span></code></pre>
<p>Which produces this:</p>
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<style>
.svg-embed {
background-color: #ffe;
font-size: 12px;
}
</style>
<rect x="10" y="10" width="180" height="80" stroke="hotpink" fill="#ccc"></rect>
<text x="20" y="30">How boring, text within a text-element</text>
<foreignObject x="20" y="40" width="160" height="60">
<div class="svg-embed">
Some styled <strong>text</strong> with background and <a href="https://ngrmr.at/">a link</a>.
</div>
</foreignObject>
</svg>Transparent borders for tables2022-02-09T00:00:00Zhttps://ngrmr.at/blog/2022-02-09-background-clip/<p>I had to style a table where the rows should have a colored background but should be separated from each other. When using a transparent border for the table cells, I found out, that the background color of the cells was painting also the area beneath the borders, i.e. the transparent borders would have the same color as the inner area of the cells. Using the background color of the table's parent element didn't work, because the table is used on multiple pages with varying background colors.</p>
<p>After some research I stumbled about the CSS property <code>background-clip</code>, which controls what part of the box-model of an element receives the background color. The default value is <code>border-box</code>, but there are also the values <code>padding-box</code> and <code>content-box</code>. The one I needed was <code>padding-box</code> which colors also the elements padding area but not its border:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">th, td</span> <span class="token punctuation">{</span><br /> <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1ch<span class="token punctuation">;</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> #ffe5fe<span class="token punctuation">;</span><br /> <span class="token property">border</span><span class="token punctuation">:</span> 0 solid transparent<span class="token punctuation">;</span><br /> <span class="token property">border-width</span><span class="token punctuation">:</span> 2px 1px 2px 0<span class="token punctuation">;</span><br /> <span class="token property">background-clip</span><span class="token punctuation">:</span> padding-box<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>There's also a fourth value <code>text</code> which allows to use the background color or image to fill only the shape of the letters.</p>
Il Fulmine Rosso2021-12-18T00:00:00Zhttps://ngrmr.at/cycling/fulmine-rosso/<h1>Il Fulmine Rosso</h1>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/KN9-vT94Th-480.avif 480w, https://ngrmr.at/img/KN9-vT94Th-1024.avif 1024w, https://ngrmr.at/img/KN9-vT94Th-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/KN9-vT94Th-480.jpeg 480w, https://ngrmr.at/img/KN9-vT94Th-1024.jpeg 1024w, https://ngrmr.at/img/KN9-vT94Th-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Fulmine Rosso" title="Photo of my Fulmine Rosso" loading="lazy" decoding="async" src="https://ngrmr.at/img/KN9-vT94Th-480.jpeg" width="4032" height="3016" /></picture></p>
<p>In 2014 Hannes gave me the remnants of 3 three late 80ies road bikes that were converted to fixies: A big box full of drop-bar handlebars, flat-rimmed wheels, brake levers, derailleurs, cranks and other stuff you didn't want to have on your hipster bike. All that was lacking to build a nice bike from this convolute were a saddle, a pair of brake calipers and a frame. After a bit of searching I had everything needed and handed of the assembly of the parts to Christian at the <a href="https://www.churchofbikes.com/">Church of Bikes</a>.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/wVrqDujOR_-480.avif 480w, https://ngrmr.at/img/wVrqDujOR_-1024.avif 1024w, https://ngrmr.at/img/wVrqDujOR_-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/wVrqDujOR_-480.jpeg 480w, https://ngrmr.at/img/wVrqDujOR_-1024.jpeg 1024w, https://ngrmr.at/img/wVrqDujOR_-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Fulmine Rosso, showing the deformation of the down tube" title="Photo of my Fulmine Rosso, showing the deformation of the down tube" loading="lazy" decoding="async" src="https://ngrmr.at/img/wVrqDujOR_-480.jpeg" width="4032" height="3016" /></picture></p>
<p>The result is this classic steel racer. It sports a blue-green Shimano 600 drivetrain, brakes and hubs, FIR rims, 3ttt stem and handlebar and a Rolls leather saddle. The steel frame is of unknown descent and is actually a little bit bent at the upper end of the down tube. It's nothing of great value but sure does look nice with its chrome finnish.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/XwWnatKgpq-480.avif 480w, https://ngrmr.at/img/XwWnatKgpq-1024.avif 1024w, https://ngrmr.at/img/XwWnatKgpq-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/XwWnatKgpq-480.jpeg 480w, https://ngrmr.at/img/XwWnatKgpq-1024.jpeg 1024w, https://ngrmr.at/img/XwWnatKgpq-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Fulmine Rosso" title="Photo of my Fulmine Rosso" loading="lazy" decoding="async" src="https://ngrmr.at/img/XwWnatKgpq-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/EFiB2fpZSy-480.avif 480w, https://ngrmr.at/img/EFiB2fpZSy-1024.avif 1024w, https://ngrmr.at/img/EFiB2fpZSy-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/EFiB2fpZSy-480.jpeg 480w, https://ngrmr.at/img/EFiB2fpZSy-1024.jpeg 1024w, https://ngrmr.at/img/EFiB2fpZSy-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Fulmine Rosso" title="Photo of my Fulmine Rosso" loading="lazy" decoding="async" src="https://ngrmr.at/img/EFiB2fpZSy-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/McmvJwOMAU-480.avif 480w, https://ngrmr.at/img/McmvJwOMAU-1024.avif 1024w, https://ngrmr.at/img/McmvJwOMAU-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/McmvJwOMAU-480.jpeg 480w, https://ngrmr.at/img/McmvJwOMAU-1024.jpeg 1024w, https://ngrmr.at/img/McmvJwOMAU-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Fulmine Rosso" title="Photo of my Fulmine Rosso" loading="lazy" decoding="async" src="https://ngrmr.at/img/McmvJwOMAU-480.jpeg" width="3016" height="4032" /></picture></p>
Cannondale Topstone2021-12-18T00:00:00Zhttps://ngrmr.at/cycling/cannondale-topstone/<h1>Cannondale Topstone Carbon</h1>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/YwsqNypqjc-480.avif 480w, https://ngrmr.at/img/YwsqNypqjc-1024.avif 1024w, https://ngrmr.at/img/YwsqNypqjc-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/YwsqNypqjc-480.jpeg 480w, https://ngrmr.at/img/YwsqNypqjc-1024.jpeg 1024w, https://ngrmr.at/img/YwsqNypqjc-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Cannondale Topstone" title="Photo of my Cannondale Topstone" loading="lazy" decoding="async" src="https://ngrmr.at/img/YwsqNypqjc-480.jpeg" width="4032" height="3016" /></picture></p>
<p>During the first Covid-19 lockdown in march 2020 I picked up my cycling routine again. Cycling and running were the only things you were allowed to do outdoors during those weeks. Running were out of question due problems with my knees. The most sporty bike I had at that time was my <a href="https://ngrmr.at/cycling/fulmine-rosso">Fulmine Rosso</a> which limited my riding to paved roads. Its ambitious gearing paired with my bad knees made it difficult to explore the hills around Vienna. When shops were allowed to open again, I headed almost immediately to <a href="https://www.starbike.at/">Starbike</a> where I was lucky to find a gravel bike — a concept that was rather new to me at that time — in my size for an acceptable price in stock. This was the Cannondale Topstone Carbon. I got the cheapest carbon model from the 2019 line up which sported a Shimano 105 drive train with 2 × 11 gears and hydraulic disc brakes, not so great wheels with WTB rims and Cannondale crankset, seatpost, stem and handlebar.</p>
<p>This was a lot of tech that I had never came in contact with before: Carbon frame and fork, hydraulic disk brakes, STI levers, tubeless tires, PressFit bottom bracket, thru-axles. Although a bit scary at first, that I suddenly ride a bike where I don't have an idea how to fix or replace all the components, I have to admit that it was a joy to ride. It gave me the ability to ride almost anywhere some path leads, it's gearing allowed me to climb the mightiest mountains one can find in and around Vienna (~300m altitude gain) and the brakes allowed me to descend with confidence. This is also the first <em>new</em> bike I have ever owned.</p>
<p>The frame has a suspension system in its rear, marketed as the Kingpin suspension system. It relies on a certain amount of flex in the seat and chain stays and in the upper rear end of the frame's main rectangle and a pivot connection between seat stays and seat tube. I cannot quantify how much this actually dampens, but descending on the cobble-stones roads of the Vienna Höhenstraße from Kahlenberg is not painful anymore. And that's something. Might also be a result of wider tires with lower pressure or the carbon frame when comparing to my experience on steel frames, but the suspension system will also provide its share to the bikes smooth feel.</p>
<p>For longer tours I equip it with various bike-packing bags. On my <a href="https://ngrmr.at/cycling/2021-it-sv-hr">2021 summer trip</a> I was travelling with Vaude saddle and top-tube bags, Rockbros frame bag and a Zefal handlebar bag. In winter I mount a pair of SKS Speedrocker fenders. I use Crankbrother Eggbeater 2 pedals.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/N9JxazT7x3-480.avif 480w, https://ngrmr.at/img/N9JxazT7x3-1024.avif 1024w, https://ngrmr.at/img/N9JxazT7x3-2944.avif 2944w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/N9JxazT7x3-480.jpeg 480w, https://ngrmr.at/img/N9JxazT7x3-1024.jpeg 1024w, https://ngrmr.at/img/N9JxazT7x3-2944.jpeg 2944w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Cannondale Topstone fully loaded with bike-packing bags" title="Photo of my Cannondale Topstone fully loaded with bike-packing bags" loading="lazy" decoding="async" src="https://ngrmr.at/img/N9JxazT7x3-480.jpeg" width="2944" height="3428" /></picture></p>
<p>In autumn 2021 I replaced the stock wheels with a pair of Zipp 303s carbon wheels, which made climbing even easier. Their handling feels significantly more stable, accelerating is ridiculously effortless. Going around corners, where the WTBs sometimes became a bit wobbly, now feels like I'm riding on tracks. Also their deep rims look good on the Topstone's massive frame.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/GZmlHc8m5L-480.avif 480w, https://ngrmr.at/img/GZmlHc8m5L-1024.avif 1024w, https://ngrmr.at/img/GZmlHc8m5L-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/GZmlHc8m5L-480.jpeg 480w, https://ngrmr.at/img/GZmlHc8m5L-1024.jpeg 1024w, https://ngrmr.at/img/GZmlHc8m5L-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="My Topstone with saddle bag, leaning against a fence on a bridge on the old Postalm road." title="My Topstone with saddle bag, leaning against a fence on a bridge on the old Postalm road." loading="lazy" decoding="async" src="https://ngrmr.at/img/GZmlHc8m5L-480.jpeg" width="4032" height="3024" /></picture></p>
Media queries with any-pointer2021-12-14T00:00:00Zhttps://ngrmr.at/blog/2021-12-09-any-pointer/<p>There's the media-feature <code>pointer</code> to test the accuracy of the primary input device in media queries. But what if we're interested in general availability of a a coarse (i.e. touch screen) or fine (i.e. mouse) pointing device? We use the <code>any-pointer</code> media feature!</p>
<pre class="language-css"><code class="language-css"><span class="token selector">button</span> <span class="token punctuation">{</span><br /> <span class="token property">padding</span><span class="token punctuation">:</span> 1rem 4ch<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">any-pointer</span><span class="token punctuation">:</span> fine<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">button</span> <span class="token punctuation">{</span><br /> <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 2ch<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
Cold setting a steel frame2021-12-12T00:00:00Zhttps://ngrmr.at/cycling/cold-setting/<h1>Cold Setting a Steel Frame</h1>
<p>Part of my efforts to improve the rideability of my <a href="https://ngrmr.at/cycling/freddie-grubb">Freddie Grubb Tourmalet</a> involved installing modern wheels. There were two main issues:</p>
<ul>
<li>Diameter of the wheels: the frame was built for 27.5" wheels and I was trying to install 28" wheels</li>
<li>The space between the rear dropouts and the width of the hub</li>
</ul>
<p>The Tourmalet frame, it's built with Reynolds 531 tubes, had a spacing of 120 mm but the Mavic Aksium wheel I had laying around have a 130 mm wide hub.</p>
<p>Sheldon Brown suggests to use a wooden beam as lever for <a href="https://www.sheldonbrown.com/frame-spacing.html#spreading">spreading the frame</a>. I was afraid to apply this technique because I feared I might end up with an asymmetric frame. After a bit of YouTube research I decided to use a threaded 10mm bolt, a pair of washers and some screw nuts to widen the space between the two rear triangles.</p>
<p>First I removed the rear wheel, derailleur, fender and rack. Next I put a clamp on the seat stays to secure the soldering at the bridge.<br />
Then I screwed two nuts and washers on the bolt with a distance of approx. 100 mm between them and additional two nuts, locking each other, at the end of the bolt. I placed the the bolts with washers inside the dropouts and used a wrench on one of the nuts to expand the rear triangle. The two locking nuts can be fixated with another wrench to keep the bolt from rotating with the nut you're screwing apart.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/p6z-dBwJP4-480.avif 480w, https://ngrmr.at/img/p6z-dBwJP4-1024.avif 1024w, https://ngrmr.at/img/p6z-dBwJP4-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/p6z-dBwJP4-480.jpeg 480w, https://ngrmr.at/img/p6z-dBwJP4-1024.jpeg 1024w, https://ngrmr.at/img/p6z-dBwJP4-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the bolt spreading the space between the rear triangles" title="Photo of the bolt spreading the space between the rear triangles" loading="lazy" decoding="async" src="https://ngrmr.at/img/p6z-dBwJP4-480.jpeg" width="4032" height="3016" /></picture></p>
<p>I started with expanding it to 150 mm, then loosened the nuts again and measured. There was no measurable effect. So I tried again, forcing the spacing to 160 mm, again no effect. In the end I had to spread the rear triangles to over 180 mm so they stayed at 130mm after removing the bolt.</p>
<p>I was really astonished at how much force has to be applied in order to cause a permanent deflection of the delicate seat and chain stays. Not sure if this due to the high-tensile Reynolds tubes or if this can also be observed with lower quality frames.</p>
Find event listeners for DOM element2021-12-09T00:00:00Zhttps://ngrmr.at/blog/2021-12-09-get-event-listeners/<p>Webkit-/Blink-based browsers (i.e. Chrome, Safari, etc.) provide a neat utility to find out if and which event listeners are attached to a DOM node: <code>getEventListeners()</code>. It can only be invoked from the JavaScript console in the dev tools, not from a script. The return value is a map giving a list of handlers for each event type.</p>
<pre class="language-js"><code class="language-js"><span class="token function">getEventListeners</span><span class="token punctuation">(</span>$0<span class="token punctuation">)</span></code></pre>
<p>Firefox doesn't provide this function in its Developer Tools but has a graphical interface for events in its DOM Inspector. There's a tag labelled "event" next to each DOM node that has some event listeners attached to it. Clicking them reveals more information and allows to open the handler function in the Debugger.</p>
Taga Folding Cargo Bike2021-12-07T00:00:00Zhttps://ngrmr.at/cycling/taga/<h1>Taga Folding Cargo Bike</h1>
<p>The Taga is an ingenious dutch tricycle which doubles as small cargo bike and baby stroller. Through a smart folding mechansim it can be turned from a bicycle with two wheels in the front to a stroller with a single front wheel. It can be equipped with a wooden box for transporting 2 children or a week's worth of groceries, including a crate of beer or with a light and comfortable buggy seat.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/bobLHQG5uu-480.avif 480w, https://ngrmr.at/img/bobLHQG5uu-1024.avif 1024w, https://ngrmr.at/img/bobLHQG5uu-2592.avif 2592w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/bobLHQG5uu-480.jpeg 480w, https://ngrmr.at/img/bobLHQG5uu-1024.jpeg 1024w, https://ngrmr.at/img/bobLHQG5uu-2592.jpeg 2592w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my former bike shack with the Taga in front" title="Photo of my former bike shack with the Taga in front" loading="lazy" decoding="async" src="https://ngrmr.at/img/bobLHQG5uu-480.jpeg" width="2592" height="1944" /></picture></p>
<p>I bought mine from the auction of the Embacher Bicycle collection. Which means, that I own a bike that has been shown in museums around the world.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/8EcwvyQRfp-480.avif 480w, https://ngrmr.at/img/8EcwvyQRfp-1024.avif 1024w, https://ngrmr.at/img/8EcwvyQRfp-2592.avif 2592w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/8EcwvyQRfp-480.jpeg 480w, https://ngrmr.at/img/8EcwvyQRfp-1024.jpeg 1024w, https://ngrmr.at/img/8EcwvyQRfp-2592.jpeg 2592w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Taga with a young passenger in buggy seat" title="Taga with a young passenger in buggy seat" loading="lazy" decoding="async" src="https://ngrmr.at/img/8EcwvyQRfp-480.jpeg" width="2592" height="1944" /></picture></p>
Long-reach double pivot brakes for a vintage road bike2021-12-07T00:00:00Zhttps://ngrmr.at/cycling/long-reach-double-pivot-brakes-for-vintage-bike/<h1>Upgrading the brakes on a vintage bike</h1>
<h2>The Issue</h2>
<p>After years of postponing I started this autumn to upgrade the brakes on my vintage <a href="https://ngrmr.at/cycling/freddie-grubb">Freddie Grubb Tourmalet</a>.<br />
The bike was originally equipped with Weinmann 780 calipers and 27.5" wheels (which are actually — due to different measuring — a tiny bit larger than the now common 28" wheels). The frame and fork have plenty of tyre clearance, which means that the brake calipers need to have rather long arms. The Weinmanns provide just that. What they don't provide is braking power. They come with a simple single-pivot design and their alloy is prone to flexing.</p>
<h2>The Options</h2>
<p>So, what I wanted were calipers with a double-pivot mechanism. The choice of historic components is not very exciting: when the double-pivot design became common ca. 1990, there was apparently no demand for long-reach brakes. So, there are basically 2 options for modern double-pivot long-reach brakes: Tektro R559 and VeloOrange GrandCru. However these come with a recessed allen key mounts and thus can't be mounted on a historic frame with simple holes for nutted mounting bolts. Although they can be modified — if you get hold of some special parts — I decided to go with a third, seemingly easier and cheaper option:<br />
I ordered a pair of ZTTO AS2.6D calipers from AliExpress for 20€. Although they are also equipped with recessed allen key mounts, it's easier to convert them.</p>
<h2>Adaptation</h2>
<p>For anyone facing a similar situation I will describe the process: The front calipers comes with a long bolt which can easily be mounted at the rear. (For cable routing reasons I ended up mounting it facing forward a.k.a. the wrong way. This has, in case of my frame, also the advantage of bringing the pads a bit closer to the wheel, as the arms are actually a bit too short for the Tourmalet.)</p>
<p>Next task was disassembling the rear calipers to replace the original bolt with something longer. First I removed the right torx screw to remove the front, right caliper. Then I used a screw clamp to force out the bolt. The bolt can be replaced with any M6 bolt with hexagonal head in sufficient length. I ended up with a 60mm long bolt from my local brick and mortar store.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/htAbxQYagr-480.avif 480w, https://ngrmr.at/img/htAbxQYagr-1024.avif 1024w, https://ngrmr.at/img/htAbxQYagr-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/htAbxQYagr-480.jpeg 480w, https://ngrmr.at/img/htAbxQYagr-1024.jpeg 1024w, https://ngrmr.at/img/htAbxQYagr-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the converted rear brake" title="Photo of the converted rear brake" loading="lazy" decoding="async" src="https://ngrmr.at/img/htAbxQYagr-480.jpeg" width="4032" height="3016" /></picture></p>
<p>As noted before, the brake arms of the ZTTO calipers are a bit too short for my Tourmalet frame when equipped with 28" wheels. I solved this issue in an inelegant way by milling the holes for the brake shoes with a Dremel. Works. For cable routing reasons I mounted the rear brake reversed, facing forwards.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/CgEghdQQPN-480.avif 480w, https://ngrmr.at/img/CgEghdQQPN-1024.avif 1024w, https://ngrmr.at/img/CgEghdQQPN-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/CgEghdQQPN-480.jpeg 480w, https://ngrmr.at/img/CgEghdQQPN-1024.jpeg 1024w, https://ngrmr.at/img/CgEghdQQPN-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of front-facing rear brake" title="Photo of front-facing rear brake" loading="lazy" decoding="async" src="https://ngrmr.at/img/CgEghdQQPN-480.jpeg" width="4928" height="3264" /></picture></p>
<p>Thanks go out to Christian and Sebastian at the <a href="https://www.churchofbikes.com/">Church of Bikes</a>, who helped putting the final pieces together, provided me with advice, opinion and a Dremel, and showed me how to properly wrap a handlebar tape.</p>
Cycling2021-12-07T00:00:00Zhttps://ngrmr.at/cycling/<h1>Cycling</h1>
<p>I'm an avid cyclist. On this page I want to share some of my experiences of riding and maintaining my various bikes.</p>
<h2>My current bikes:</h2>
<ul>
<li><a href="https://ngrmr.at/cycling/cannondale-topstone">Cannondale Topstone</a></li>
<li><a href="https://ngrmr.at/cycling/freddie-grubb">Freddie Grubb Tourmalet</a></li>
<li>Puch Single-Speed</li>
<li><a href="https://ngrmr.at/cycling/fulmine-rosso">Il Fulmine Rosso</a></li>
<li><a href="https://ngrmr.at/cycling/taga">Taga Folding Cargo Bike/Baby Stroller</a></li>
</ul>
<h2>My road and off-road adventures</h2>
<ul>
<li><a href="https://ngrmr.at/cycling/2021-it-sv-hr">2021 Alpe-Adria — From Villach to Rijeka</a></li>
<li><a href="https://ngrmr.at/cycling/2023-out-of-the-alps">2023 Out of the Alps</a></li>
<li><a href="https://ngrmr.at/cycling/2023-balkan">2023 Balkan</a></li>
</ul>
<p>See my <a href="https://www.strava.com/athletes/ngrmr">profile on Strava</a> for a complete list of my rides.</p>
<h2>My workshop adventures</h2>
<ul>
<li><a href="https://ngrmr.at/cycling/long-reach-double-pivot-brakes-for-vintage-bike">Upgrading the brakes on a vintage bike</a></li>
<li><a href="https://ngrmr.at/cycling/cold-setting">Cold setting a bike frame</a></li>
</ul>
<h2>My former bikes:</h2>
<ul>
<li>Hercules 3-speed</li>
<li>Basso Coral</li>
<li>Giant Peloton Superlite</li>
<li>Francesco Moser Corsa</li>
<li><a href="https://ngrmr.at/cycling/gazelle">Gazelle Champion Mondial (A-Frame)</a></li>
</ul>
Gazelle Champion Mondial2021-12-07T00:00:00Zhttps://ngrmr.at/cycling/gazelle/<h1>Gazelle Champion Mondial</h1>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/bGn0zT9QZR-480.avif 480w, https://ngrmr.at/img/bGn0zT9QZR-1024.avif 1024w, https://ngrmr.at/img/bGn0zT9QZR-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/bGn0zT9QZR-480.jpeg 480w, https://ngrmr.at/img/bGn0zT9QZR-1024.jpeg 1024w, https://ngrmr.at/img/bGn0zT9QZR-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the my Gazelle bike" title="Photo of the my Gazelle bike" loading="lazy" decoding="async" src="https://ngrmr.at/img/bGn0zT9QZR-480.jpeg" width="4928" height="3264" /></picture></p>
<p>I bought this beauty around 2008. It had a marvelous steel frame, build with Reynolds 531 tubes.<br />
It came equipped with the original Shimano Deore derailleurs, shifters, cranks and pedals, which happened to be marketed as „touring“ components — this was before the invention of „mountain biking“. The brakes were Shimano 600 <em>arabesque</em>. When I got hold of matching shifters and derailleurs, I upgraded those parts as well.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/i9516ZR5k_-480.avif 480w, https://ngrmr.at/img/i9516ZR5k_-1024.avif 1024w, https://ngrmr.at/img/i9516ZR5k_-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/i9516ZR5k_-480.jpeg 480w, https://ngrmr.at/img/i9516ZR5k_-1024.jpeg 1024w, https://ngrmr.at/img/i9516ZR5k_-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Detail photo of the shifters" title="Detail photo of the shifters" loading="lazy" decoding="async" src="https://ngrmr.at/img/i9516ZR5k_-480.jpeg" width="4928" height="3264" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/7HmbK1fZW2-480.avif 480w, https://ngrmr.at/img/7HmbK1fZW2-1024.avif 1024w, https://ngrmr.at/img/7HmbK1fZW2-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/7HmbK1fZW2-480.jpeg 480w, https://ngrmr.at/img/7HmbK1fZW2-1024.jpeg 1024w, https://ngrmr.at/img/7HmbK1fZW2-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Detail photo of the rear derailleur" title="Detail photo of the rear derailleur" loading="lazy" decoding="async" src="https://ngrmr.at/img/7HmbK1fZW2-480.jpeg" width="4928" height="3264" /></picture></p>
<p>However, this bike turned out to be too nice for me. I'm an expert at getting my frames scratched, so riding this stunner always stressed me.<br />
In the end, I didn't have enough space to keep it sitting around and sold it again in 2016. The Deore shifters are now mounted on my <a href="https://ngrmr.at/cycling/freddie-grubb">Freddie Grubb</a>.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/BMBtaFB5K1-480.avif 480w, https://ngrmr.at/img/BMBtaFB5K1-1024.avif 1024w, https://ngrmr.at/img/BMBtaFB5K1-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/BMBtaFB5K1-480.jpeg 480w, https://ngrmr.at/img/BMBtaFB5K1-1024.jpeg 1024w, https://ngrmr.at/img/BMBtaFB5K1-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Detail photo of the bottom bracket and shifter cable guides" title="Detail photo of the bottom bracket and shifter cable guides" loading="lazy" decoding="async" src="https://ngrmr.at/img/BMBtaFB5K1-480.jpeg" width="4928" height="3264" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/ape-jawN46-480.avif 480w, https://ngrmr.at/img/ape-jawN46-1024.avif 1024w, https://ngrmr.at/img/ape-jawN46-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/ape-jawN46-480.jpeg 480w, https://ngrmr.at/img/ape-jawN46-1024.jpeg 1024w, https://ngrmr.at/img/ape-jawN46-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Detail photo of the rear brakes" title="Detail photo of the rear brakes" loading="lazy" decoding="async" src="https://ngrmr.at/img/ape-jawN46-480.jpeg" width="4928" height="3264" /></picture></p>
Freddie Grubb Tourmalet2021-12-07T00:00:00Zhttps://ngrmr.at/cycling/freddie-grubb/<h1>Freddie Grubb Tourmalet</h1>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/snQJ5rI84r-480.avif 480w, https://ngrmr.at/img/snQJ5rI84r-1024.avif 1024w, https://ngrmr.at/img/snQJ5rI84r-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/snQJ5rI84r-480.jpeg 480w, https://ngrmr.at/img/snQJ5rI84r-1024.jpeg 1024w, https://ngrmr.at/img/snQJ5rI84r-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my Freddie Grubb with Ortlieb pannier" title="Photo of my Freddie Grubb with Ortlieb pannier" loading="lazy" decoding="async" src="https://ngrmr.at/img/snQJ5rI84r-480.jpeg" width="4928" height="3264" /></picture></p>
<p>In 2009 I bought a Freddie Grubb Tourmalet road bike. Freddie Grubb was one of the finest bike manufacturers in London before and after WW2. After Mr. Grubb had died, his family sold the business to Holdsworth Bikes in 1952, one of their competitors, which kept the brand until 1976 as their cheap branch. According to its serial number <em>23585</em> my frame was built in 1975, making it one of the last batches before production ceased.<br />
In case you are interested in the history of Freddie Grubb and his company, please head over to <a href="http://nkilgariff.com/FreddieGrubb.htm">Norman Kilgariff's page</a>.</p>
<p>There is also a new brand with that name, but for what I understand there is no connection to the old company.</p>
<p>I used to ride this bike a lot when I purchased it. As it came with rather mediocre parts, i.e. Weinmann 780 brakes, Campagnolo 980 derailleurs, a broken Edwards leather saddle, I replaced parts as I got hold of worthy replacement parts. Over the years it gained fancy Suntour Cyclone derailleurs, classic Shimano Deore down-tube shifters and a new black Brooks B17 saddle, fenders and a Tubus Fly rack.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/sl3v2Vf8f5-480.avif 480w, https://ngrmr.at/img/sl3v2Vf8f5-1024.avif 1024w, https://ngrmr.at/img/sl3v2Vf8f5-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/sl3v2Vf8f5-480.jpeg 480w, https://ngrmr.at/img/sl3v2Vf8f5-1024.jpeg 1024w, https://ngrmr.at/img/sl3v2Vf8f5-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Detail photo of the Suntour Cyclone rear derailleur" title="Detail photo of the Suntour Cyclone rear derailleur" loading="lazy" decoding="async" src="https://ngrmr.at/img/sl3v2Vf8f5-480.jpeg" width="4928" height="3264" /></picture></p>
<p>A major pain point have been the brakes. Breaking power was never really great and over time the spring in the right lever wore out. This meant, when I faciliated the rear brake, the braking effect was rather gentle, but once I released the lever the effect didn't resolve until I forcefully pushed the lever back into its neutral state. As a result I eventually stopped riding my Tourmalet. In late 2021 I tackled the braking issue and <a href="https://ngrmr.at/cycling/long-reach-double-pivot-brakes-for-vintage-bike">replaced the Weinmanns with cheap modern brakes</a> and the ancient 27.5" steel-rimmed Mavic wheels with modern Alloy-ones from the same manufacturer.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/HqNkSaQxpo-480.avif 480w, https://ngrmr.at/img/HqNkSaQxpo-1024.avif 1024w, https://ngrmr.at/img/HqNkSaQxpo-4928.avif 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/HqNkSaQxpo-480.jpeg 480w, https://ngrmr.at/img/HqNkSaQxpo-1024.jpeg 1024w, https://ngrmr.at/img/HqNkSaQxpo-4928.jpeg 4928w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the bike" title="Photo of the bike" loading="lazy" decoding="async" src="https://ngrmr.at/img/HqNkSaQxpo-480.jpeg" width="4928" height="3264" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/sh4KamIcCd-480.avif 480w, https://ngrmr.at/img/sh4KamIcCd-1024.avif 1024w, https://ngrmr.at/img/sh4KamIcCd-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/sh4KamIcCd-480.jpeg 480w, https://ngrmr.at/img/sh4KamIcCd-1024.jpeg 1024w, https://ngrmr.at/img/sh4KamIcCd-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the partially disassembled bike" title="Photo of the partially disassembled bike" loading="lazy" decoding="async" src="https://ngrmr.at/img/sh4KamIcCd-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/OgWWK-HVIO-480.avif 480w, https://ngrmr.at/img/OgWWK-HVIO-1024.avif 1024w, https://ngrmr.at/img/OgWWK-HVIO-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/OgWWK-HVIO-480.jpeg 480w, https://ngrmr.at/img/OgWWK-HVIO-1024.jpeg 1024w, https://ngrmr.at/img/OgWWK-HVIO-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the bottom bracket with the engraved serial number 23585" title="Photo of the bottom bracket with the engraved serial number 23585" loading="lazy" decoding="async" src="https://ngrmr.at/img/OgWWK-HVIO-480.jpeg" width="3016" height="4032" /></picture></p>
2021 Alpe-Adria — From Villach to Rijeka2021-12-07T00:00:00Zhttps://ngrmr.at/cycling/2021-it-sv-hr/<h1>2021 Alpe-Adria — From Villach to Rijeka</h1>
<iframe width="700" height="394" src="https://www.youtube.com/embed/_GOlwoN4IRE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>In August 2021 I found myself with a whole week of spare time for cycling. Lacking a clear plan what to do with this opportunity, I found myself at a friday on lunch time at the Villach train station where I met with 3 friends and a vague ideo to explore the Triglav national park in Slovenia. This original plan was immediately shunned and we set out to follow the old rail tracks of the Alpe-Adria cycling route to Grado, where we arrived 2 days later.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/69D6vinQeW-480.avif 480w, https://ngrmr.at/img/69D6vinQeW-1024.avif 1024w, https://ngrmr.at/img/69D6vinQeW-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/69D6vinQeW-480.jpeg 480w, https://ngrmr.at/img/69D6vinQeW-1024.jpeg 1024w, https://ngrmr.at/img/69D6vinQeW-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the group riding on a former rail-road bridge" title="Photo of the group riding on a former rail-road bridge" loading="lazy" decoding="async" src="https://ngrmr.at/img/69D6vinQeW-480.jpeg" width="3016" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/-6TW4SBYlt-480.avif 480w, https://ngrmr.at/img/-6TW4SBYlt-1024.avif 1024w, https://ngrmr.at/img/-6TW4SBYlt-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/-6TW4SBYlt-480.jpeg 480w, https://ngrmr.at/img/-6TW4SBYlt-1024.jpeg 1024w, https://ngrmr.at/img/-6TW4SBYlt-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of Arnold and Paul fueling up on a water fountain" title="Photo of Arnold and Paul fueling up on a water fountain" loading="lazy" decoding="async" src="https://ngrmr.at/img/-6TW4SBYlt-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/qvlYsMUDVm-480.avif 480w, https://ngrmr.at/img/qvlYsMUDVm-1024.avif 1024w, https://ngrmr.at/img/qvlYsMUDVm-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/qvlYsMUDVm-480.jpeg 480w, https://ngrmr.at/img/qvlYsMUDVm-1024.jpeg 1024w, https://ngrmr.at/img/qvlYsMUDVm-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the main square of Palmanova" title="Photo of the main square of Palmanova" loading="lazy" decoding="async" src="https://ngrmr.at/img/qvlYsMUDVm-480.jpeg" width="4032" height="3016" /></picture></p>
<p>Then we headed east, crossed Triest, and stopped at Muggia next to the slovenian border, where we realized that finding accommodation in high season is not necessarily a trivial task. Luckily, the friendly owner of the beach bar we had stopped at for refreshing beverages allowed us to sleep under the bar's sun tent and there was a Decathlon just 5 kilometers away where we equipped the remaining three of us with super-compact inflatable mats and sleeping back inlets.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/XBSgemDEVE-480.avif 480w, https://ngrmr.at/img/XBSgemDEVE-1024.avif 1024w, https://ngrmr.at/img/XBSgemDEVE-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/XBSgemDEVE-480.jpeg 480w, https://ngrmr.at/img/XBSgemDEVE-1024.jpeg 1024w, https://ngrmr.at/img/XBSgemDEVE-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the group on a gravel path" title="Photo of the group on a gravel path" loading="lazy" decoding="async" src="https://ngrmr.at/img/XBSgemDEVE-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/72U2Gx7SSD-480.avif 480w, https://ngrmr.at/img/72U2Gx7SSD-1024.avif 1024w, https://ngrmr.at/img/72U2Gx7SSD-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/72U2Gx7SSD-480.jpeg 480w, https://ngrmr.at/img/72U2Gx7SSD-1024.jpeg 1024w, https://ngrmr.at/img/72U2Gx7SSD-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of 3 road bikes in front of a store" title="Photo of 3 road bikes in front of a store" loading="lazy" decoding="async" src="https://ngrmr.at/img/72U2Gx7SSD-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/cFuDNaPlTh-480.avif 480w, https://ngrmr.at/img/cFuDNaPlTh-1024.avif 1024w, https://ngrmr.at/img/cFuDNaPlTh-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/cFuDNaPlTh-480.jpeg 480w, https://ngrmr.at/img/cFuDNaPlTh-1024.jpeg 1024w, https://ngrmr.at/img/cFuDNaPlTh-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of our makeshift camp in Muggia" title="Photo of our makeshift camp in Muggia" loading="lazy" decoding="async" src="https://ngrmr.at/img/cFuDNaPlTh-480.jpeg" width="3016" height="4032" /></picture></p>
<p>We crossed Slovenia and found another beach bar near the Croatian town Tar, where we further benefitted from our new minimal camping gear. The next day our group was diminished to two riders. The remainders, Paul and me, crossed the peninsula of Istria, got lost in some woods, had a wonderful lunch and eventually found ourselves in the popular tourist destination of Rabac. We were not just lucky enough to get <em>some</em> spot on the giant camping site there, but we actually got the spot number 1 — right at the beach. The open veranda of the site's grill restaurant sheltered us well during the heavy rain in the night.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/X70G1nzCVH-480.avif 480w, https://ngrmr.at/img/X70G1nzCVH-1024.avif 1024w, https://ngrmr.at/img/X70G1nzCVH-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/X70G1nzCVH-480.jpeg 480w, https://ngrmr.at/img/X70G1nzCVH-1024.jpeg 1024w, https://ngrmr.at/img/X70G1nzCVH-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of some road and the sea" title="Photo of some road and the sea" loading="lazy" decoding="async" src="https://ngrmr.at/img/X70G1nzCVH-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/_PVKCD5JPJ-480.avif 480w, https://ngrmr.at/img/_PVKCD5JPJ-1024.avif 1024w, https://ngrmr.at/img/_PVKCD5JPJ-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/_PVKCD5JPJ-480.jpeg 480w, https://ngrmr.at/img/_PVKCD5JPJ-1024.jpeg 1024w, https://ngrmr.at/img/_PVKCD5JPJ-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of our makeshift camp on an old ponton bridge near Tar" title="Photo of our makeshift camp on an old ponton bridge near Tar" loading="lazy" decoding="async" src="https://ngrmr.at/img/_PVKCD5JPJ-480.jpeg" width="3016" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/Cn08NkTdx4-480.avif 480w, https://ngrmr.at/img/Cn08NkTdx4-1024.avif 1024w, https://ngrmr.at/img/Cn08NkTdx4-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/Cn08NkTdx4-480.jpeg 480w, https://ngrmr.at/img/Cn08NkTdx4-1024.jpeg 1024w, https://ngrmr.at/img/Cn08NkTdx4-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of Paul performing his morning routine" title="Photo of Paul performing his morning routine" loading="lazy" decoding="async" src="https://ngrmr.at/img/Cn08NkTdx4-480.jpeg" width="3016" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/APra6iuD_r-480.avif 480w, https://ngrmr.at/img/APra6iuD_r-1024.avif 1024w, https://ngrmr.at/img/APra6iuD_r-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/APra6iuD_r-480.jpeg 480w, https://ngrmr.at/img/APra6iuD_r-1024.jpeg 1024w, https://ngrmr.at/img/APra6iuD_r-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of Paul descending" title="Photo of Paul descending" loading="lazy" decoding="async" src="https://ngrmr.at/img/APra6iuD_r-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/V3eFUHpDKR-480.avif 480w, https://ngrmr.at/img/V3eFUHpDKR-1024.avif 1024w, https://ngrmr.at/img/V3eFUHpDKR-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/V3eFUHpDKR-480.jpeg 480w, https://ngrmr.at/img/V3eFUHpDKR-1024.jpeg 1024w, https://ngrmr.at/img/V3eFUHpDKR-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of Paul pushing his bike on some forrest path" title="Photo of Paul pushing his bike on some forrest path" loading="lazy" decoding="async" src="https://ngrmr.at/img/V3eFUHpDKR-480.jpeg" width="3016" height="4032" /></picture></p>
<p>The next day we boarded a ferry to the island Cres, traversed it and took another ferry to Krk where we spent the last night, again with heavy rain but this time without shelter. When the rain stopped in the wee hours of the morning, we started our supposed last stage to Rijeka from where we wanted to go back to Villach by train.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/EUrHRYfmGQ-480.avif 480w, https://ngrmr.at/img/EUrHRYfmGQ-1024.avif 1024w, https://ngrmr.at/img/EUrHRYfmGQ-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/EUrHRYfmGQ-480.jpeg 480w, https://ngrmr.at/img/EUrHRYfmGQ-1024.jpeg 1024w, https://ngrmr.at/img/EUrHRYfmGQ-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of Paul on the ferry to Cres, looking cool." title="Photo of Paul on the ferry to Cres, looking cool." loading="lazy" decoding="async" src="https://ngrmr.at/img/EUrHRYfmGQ-480.jpeg" width="3016" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/yHtC2e8ISz-480.avif 480w, https://ngrmr.at/img/yHtC2e8ISz-1024.avif 1024w, https://ngrmr.at/img/yHtC2e8ISz-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/yHtC2e8ISz-480.jpeg 480w, https://ngrmr.at/img/yHtC2e8ISz-1024.jpeg 1024w, https://ngrmr.at/img/yHtC2e8ISz-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the island Cres" title="Photo of the island Cres" loading="lazy" decoding="async" src="https://ngrmr.at/img/yHtC2e8ISz-480.jpeg" width="4032" height="3016" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/NhIJzzvtlH-480.avif 480w, https://ngrmr.at/img/NhIJzzvtlH-1024.avif 1024w, https://ngrmr.at/img/NhIJzzvtlH-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/NhIJzzvtlH-480.jpeg 480w, https://ngrmr.at/img/NhIJzzvtlH-1024.jpeg 1024w, https://ngrmr.at/img/NhIJzzvtlH-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of my legs after crossing some bushes with thorns" title="Photo of my legs after crossing some bushes with thorns" loading="lazy" decoding="async" src="https://ngrmr.at/img/NhIJzzvtlH-480.jpeg" width="3016" height="4032" /></picture><br />
<picture><source type="image/avif" srcset="https://ngrmr.at/img/7m-qWCSdpA-480.avif 480w, https://ngrmr.at/img/7m-qWCSdpA-1024.avif 1024w, https://ngrmr.at/img/7m-qWCSdpA-4032.avif 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/7m-qWCSdpA-480.jpeg 480w, https://ngrmr.at/img/7m-qWCSdpA-1024.jpeg 1024w, https://ngrmr.at/img/7m-qWCSdpA-4032.jpeg 4032w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of Paul riding into the dawn on the Krk bridge" title="Photo of Paul riding into the dawn on the Krk bridge" loading="lazy" decoding="async" src="https://ngrmr.at/img/7m-qWCSdpA-480.jpeg" width="4032" height="3016" /></picture></p>
<p>But due to a conglomeration of late trains, time consuming passport checks and slow rail replacement bus services we stranded in the Slovenian town Jesenice just one mountain pass south of Villach. So we got to enjoy another last stage and arrived just after dusk at lake Ossiach, where Paul had supposedly parked his car. Two hours later, the batteries of our lights had already died, we finally figured out that it was indeed not lake Ossiach but lake Vessach were the car had been parked.</p>
<p><picture><source type="image/avif" srcset="https://ngrmr.at/img/E_R9xm4QdZ-480.avif 480w, https://ngrmr.at/img/E_R9xm4QdZ-1024.avif 1024w, https://ngrmr.at/img/E_R9xm4QdZ-3016.avif 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><source type="image/jpeg" srcset="https://ngrmr.at/img/E_R9xm4QdZ-480.jpeg 480w, https://ngrmr.at/img/E_R9xm4QdZ-1024.jpeg 1024w, https://ngrmr.at/img/E_R9xm4QdZ-3016.jpeg 3016w" sizes="(max-width: 800px) 480px, (max-width: 8192px) 1024px" /><img alt="Photo of the Triglav mountains, viewed from the root of the Wurzenpass" title="Photo of the Triglav mountains, viewed from the root of the Wurzenpass" loading="lazy" decoding="async" src="https://ngrmr.at/img/E_R9xm4QdZ-480.jpeg" width="3016" height="4032" /></picture></p>
<h2>Stats</h2>
<p>Duration: 7 Days<br />
Distance: ~630 Kilometers<br />
Longest ride: 100 Kilometers (Villach - Gemona)<br />
Flat tyres: 2 (among all riders)</p>
Nesting Promises2020-12-17T00:00:00Zhttps://ngrmr.at/blog/2020-12-17-nesting-promises/<p>If the result handler for a Promise resolves with another Promise, the <code>.then()</code> method of the original Promise will be called with resolved value of the nested one:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> myPromise <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">resolve</span><span class="token punctuation">(</span>Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br />myPromise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><br /><span class="token comment">// will print "7"</span></code></pre>
<p>Another example would be fetching all items from an API that allows to query only a limited number of items per request and we don't know beforehand how many items are there for us to fetch.<br />
We can achieve this by writing a function that queries for the allowed number of items. If the number of items in the response equals the limit, we fetch the next batch of items and continue to do so until the results are fewer than the limit. In this case we can resolve with the list of all items we received in our previous calls.</p>
<p>When invoking this function, we don't have to care about how often it had to recurse and call itself. We just receive the complete list of items:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">fetchAllItems</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">queryParams <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">}</span><span class="token punctuation">,</span> allItems <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token operator">=></span><br /> <span class="token comment">// fetch also returns a Promise, no need to wrap it with `new Promise()`</span><br /> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'/api/items?'</span> <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>queryParams<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">items</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token comment">// add the items we received this to the items we received before</span><br /> allItems<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>allItems<span class="token punctuation">,</span> items<span class="token punctuation">)</span><br /> <br /> <span class="token keyword">if</span><span class="token punctuation">(</span>items<span class="token punctuation">.</span>length <span class="token operator">===</span> queryParams<span class="token punctuation">.</span>max<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// if the number of items we received is equal to the limit,</span><br /> <span class="token comment">// return with another call to the function</span><br /> <span class="token keyword">return</span> <span class="token function">fetchAllItems</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token operator">...</span>queryParams<span class="token punctuation">,</span><br /> <span class="token literal-property property">start</span><span class="token operator">:</span> queryParams<span class="token punctuation">.</span>start <span class="token operator">+</span> queryParams<span class="token punctuation">.</span>max<br /> <span class="token punctuation">}</span><span class="token punctuation">,</span> allItems<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> <span class="token comment">// otherwise return the list of collected items</span><br /> <span class="token keyword">return</span> allItems<br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><br /><br /><br /><span class="token function">fetchAllItems</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">allItems</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>allItems<span class="token punctuation">)</span><br /> <span class="token comment">// do something useful</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><br /> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">error</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Something went wrong:'</span><span class="token punctuation">,</span> error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
clearInterval and clearTimeout are interchangeable2020-05-08T00:00:00Zhttps://ngrmr.at/blog/2020-05-08-clearinterval-cleartimeout/<p>The IDs returned by <code>window.setInterval</code> and <code>window.setTimeout</code> use a shared pool. And it doesn't matter whether you use <code>window.clearTimeout</code> or <code>window.clearInterval</code> to cancel an interval or timeout.</p>
<p>Live example on CodePen:</p>
<iframe height="365" style="width: 100%;" scrolling="no" title="clearInterval & clearTimeout can be interchanged" src="https://codepen.io/rangermeier/embed/bGVvYwx?height=265&theme-id=default&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/rangermeier/pen/bGVvYwx">clearInterval & clearTimeout can be interchanged</a> by Rupert Angermeier
(<a href="https://codepen.io/rangermeier">@rangermeier</a>) on <a href="https://codepen.io/">CodePen</a>.
</iframe>Detect Browser Zoom2020-04-07T00:00:00Zhttps://ngrmr.at/blog/2020-04-07-window-devicepxelratio/<p>There's a propery on the windows object that gives the current zoom level of the browser, <code>window.devicePixelRatio</code>.</p>
<p>When it changes, the <code>window.resize</code> event is triggered:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> zoomLevel <span class="token operator">=</span> window<span class="token punctuation">.</span>devicePixelRatio<br />window<span class="token punctuation">.</span><span class="token function">addEventHandler</span><span class="token punctuation">(</span><span class="token string">'resize'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span><span class="token punctuation">(</span>zoomLevel <span class="token operator">!==</span> window<span class="token punctuation">.</span>devicePixelRatio<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> zoomLevel <span class="token operator">=</span> window<span class="token punctuation">.</span>devicePixelRatio<br /> <span class="token comment">// redraw your SVG graphs or whatever</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p><em>Update 2020-05-08:</em> As discussed in the article <a href="https://css-tricks.com/can-javascript-detect-the-browsers-zoom-level/#article-header-id-2">Can JavaScript Detect the Browser’s Zoom Level?</a> on CSS Tricks, <code>devicePixelRatio</code> is not suitable to detect the actual zoom level and even the example above is not working in all modern browsers.</p>
CSS Gradient double position syntax2020-02-15T00:00:00Zhttps://ngrmr.at/blog/2020-02-15-css-gradient-double-position/<p>If you want to use a gradient to define a sequence of stripes without a smooth transition<br />
between the colors, you don't have to define a color stop for the start and end of each<br />
stripe but you can use the double position syntax. You just define the color and two positions<br />
for each color stop:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.stripes</span> <span class="token punctuation">{</span><br /> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>45deg<span class="token punctuation">,</span><br /> #e50e7e 0% 33%<span class="token punctuation">,</span><br /> #f7ea1e 33% 66%<span class="token punctuation">,</span><br /> #66b32d 66% 100%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>And better yet, you don't have to repeat the start position for each color stop. Setting it<br />
to <code>0</code> also works because the browser will autocorrect it to the largest previously defined<br />
position:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.stripes</span> <span class="token punctuation">{</span><br /> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>45deg<span class="token punctuation">,</span><br /> #e50e7e 0 33%<span class="token punctuation">,</span><br /> #f7ea1e 0 66%<span class="token punctuation">,</span><br /> #66b32d 0 100%<br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Live example on CodePen:</p>
<iframe height="265" style="width: 100%;" scrolling="no" title="CSS Gradient double position syntax" src="https://codepen.io/rangermeier/embed/gOprpmW?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/rangermeier/pen/gOprpmW">CSS Gradient double position syntax</a> by Rupert Angermeier
(<a href="https://codepen.io/rangermeier">@rangermeier</a>) on <a href="https://codepen.io/">CodePen</a>.
</iframe>Pause a CSS animation2020-01-19T00:00:00Zhttps://ngrmr.at/blog/2020-01-19-pause-css-animation/<p>There is a CSS property to pause an animation: <code>animation-play-state</code>. It's default value is <code>running</code>.<br />
When it's value is set to <code>paused</code> the animation will freeze at the current state.</p>
<p>Example:</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> rotating</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotate</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotate</span><span class="token punctuation">(</span>360deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.my-element</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> rotating 10s infinite linear<span class="token punctuation">;</span><br /> <span class="token property">animation-play-state</span><span class="token punctuation">:</span> paused<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.my-element--rotating</span> <span class="token punctuation">{</span><br /> <span class="token property">animation-play-state</span><span class="token punctuation">:</span> running<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Live example on CodePen:</p>
<iframe height="265" style="width: 100%;" scrolling="no" title="Pause CSS animation" src="https://codepen.io/rangermeier/embed/mdyQWLx?height=265&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/rangermeier/pen/mdyQWLx">Pause CSS animation</a> by Rupert Angermeier
(<a href="https://codepen.io/rangermeier">@rangermeier</a>) on <a href="https://codepen.io/">CodePen</a>.
</iframe>Color SVGs with a CSS mask2020-01-17T00:00:00Zhttps://ngrmr.at/blog/2020-01-17-css-color-svg-mask/<p>You can use a <a href="https://developer.mozilla.org/de/docs/Web/CSS/mask">mask</a> to change the color of a SVG in CSS. This is a nice solution for dynamically changing the color of an icon when the SVG can't be included in the DOM for whatever reason.</p>
<p>The syntax for masks is similar to that of background images. The effect of specifying a mask is, that only the parts of the element are visible, where the mask image is opaque.</p>
<p>Browser Support is quite good at point of writing: browsers based on webkit need vendor-prefixed properties, Firefox fully supports it.</p>
<p>Example:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span><br /> <span class="token property">--icon-color</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 138<span class="token punctuation">,</span> 214<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">--icon-checkmark</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>./checkmark.svg<span class="token punctuation">)</span></span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.with-checkmark:before</span> <span class="token punctuation">{</span><br /> <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span><br /> <span class="token property">width</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span><br /> <span class="token property">height</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span><br /> <span class="token comment">/* fallback for browsers that don't support mask */</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--icon-checkmark<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@supports</span> <span class="token punctuation">(</span><span class="token property">mask-size</span><span class="token punctuation">:</span> cover<span class="token punctuation">)</span> <span class="token keyword">or</span> <span class="token punctuation">(</span><span class="token property">-webkit-mask-size</span><span class="token punctuation">:</span> cover<span class="token punctuation">)</span></span><span class="token punctuation">{</span><br /> <span class="token selector">.with-checkmark:before</span> <span class="token punctuation">{</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token property">mask</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--icon-checkmark<span class="token punctuation">)</span> no-repeat center<span class="token punctuation">;</span><br /> <span class="token property">-webkit-mask</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--icon-checkmark<span class="token punctuation">)</span> no-repeat center<span class="token punctuation">;</span><br /> <span class="token property">mask-size</span><span class="token punctuation">:</span> cover<span class="token punctuation">;</span><br /> <span class="token property">-webkit-mask-size</span><span class="token punctuation">:</span> cover<span class="token punctuation">;</span><br /> <span class="token comment">/* the shape of the SVG will be visible in the background color */</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--icon-color<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>Another live example on CodePen:</p>
<iframe height="365" style="width: 100%;" scrolling="no" title="Color SVGs in CSS with mask" src="https://codepen.io/rangermeier/embed/preview/qBEJYQP?height=365&theme-id=default&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/rangermeier/pen/qBEJYQP">Color SVGs in CSS with mask</a> by Rupert Angermeier
(<a href="https://codepen.io/rangermeier">@rangermeier</a>) on <a href="https://codepen.io/">CodePen</a>.
</iframe>CSS custom properties don't have to be valid CSS properties2020-01-14T00:00:00Zhttps://ngrmr.at/blog/2020-01-14-spread-css-custom-properties/<p>A custom CSS property doesn't have to be a valid CSS property on its own.</p>
<p>For example, you can define a color as three numbers between 0 and 255 for red<br />
green and blue. A list of three numbers is not a valid color definition in CSS.<br />
But you can use them in the <code>rgb()</code> function to get a valid color. Using the<br />
<code>rgba()</code> function it's possible to get variants with transparency of our<br />
original color.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span><br /> <span class="token property">--color-primary</span><span class="token punctuation">:</span> 94<span class="token punctuation">,</span> 142<span class="token punctuation">,</span> 194<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.my-box</span> <span class="token punctuation">{</span><br /> <span class="token property">border</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">)</span> 2px solid<span class="token punctuation">;</span><br /> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span> 0.4<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
2019-11-27T14:51:55Zhttps://ngrmr.at/review/<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>Rupert Angermeier</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="https://ngrmr.at/review/css/main.css" />
</head>
<body>
<p>After watching Charlie Owen's talk "I'm just an Old Guard Dev in a New Guard world"
at the webclerks community conference 2019, where she gave a run down of <em>how</em> websites
where build over the course of the last 25 years and contrasted that with the what fanatastic
possibilities web devs have nowadays, I realized I could as well give some review of the
techniques that were used in the olden days.</p>
<h2>Editors</h2>
<p>Frontpage, Dreamweaver, Ulli Meybohms HTML-Editor phase 5</p>
<h2>Round Corners</h2>
<p>background images OpenRico, </p>
<h2>Images</h2>
<p>no PNG, no SVG, alpha only in GIF, "Burn all GIFs"</p>
<h2>Fonts</h2>
<p>Images, generating on the server, sIFR</p>
<h2>AJAX/DHTML</h2>
<p>jQuery, rendering partials on ther server</p>
</body>
</html>Nginx default upload size2019-11-12T00:00:00Zhttps://ngrmr.at/blog/2019-11-12-nginx-upload-maxsize/<p>The <em>default</em> maximum file size for uploads in Nginx is 2 MB. Users will receive an error <code>413 – Request Entity Too Large Error and Solution</code> when uploading a file larger than this limit and you didn't think about setting it when configuring your server.</p>
<p>You can easily raise it with the <code>client_max_body_size</code> directive, e.g.</p>
<pre class="language-nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">{</span><br /> <span class="token comment"># ...</span><br /> <span class="token directive"><span class="token keyword">client_max_body_size</span> <span class="token number">512M</span></span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
2019-09-29T09:07:16Zhttps://ngrmr.at/ebg2013/<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>Sommerfest Eschelberg 2013</title>
<meta name="viewport" content="width=device-width" />
<meta name="robots" content="nofollow" />
<link rel="stylesheet" href="https://ngrmr.at/ebg2013/stylesheet.css" />
</head>
<body>
<div id="main">
<h1>Sommerfest Eschelberg</h1>
<h2>6. Juli 2013</h2>
<h3>Programm</h3>
<p>Hauptfeierlichkeiten Samstag, 6. Juli, ab frühem Abend, wer früher kommen mag (auch schon Freitags) ist willkommen, sollte sich aber
bitte mit uns absprechen um nicht ein temporär verlassenes Haus anzutreffen.<br />
Es lohnt sich erfahrungsgemäß die Abreise erst für Sonntag Abend/später Nachmittag anzusetzen. Badesachen mit zu bringen
ist bei entsprechender Witterung eine gute Idee.
</p>
<p>Es spielen <a href="https://www.facebook.com/k0walsk">Kowalski</a>, <a href="http://www.reverbnation.com/protestantworkethic">Protestant Work Ethic</a> in Kleinbesetzung
und <a href="http://mir.bidala.org/">Mir Mayakowski</a>.
</p>
<p>Für das sogenannte leiblich Wohl wird gesorgt: Kotelettes und Würste vom <a href="http://bauernladen.schned.at/">Schned</a>
sowie frisches Gemüse am Grill, Salate, Aufstriche, Bauernbrot und ausreichend Bier aus
<a href="http://www.hofstetten.at/">Hofstetten</a>.
</p>
<h3>Anreise</h3>
<p> Eschelberg 3, 4112 St. Gotthard im Mühlkreis<br />
Koordinaten: <a href="https://maps.google.com/?ll=48.383291,14.11733">48.383291,14.11733</a>
</p>
<p><strong>Bahn:</strong> Vom Linzer Bahnhof mit der Straßenbahn 3 über die Donau bis zum Mühlkreisbahnhof. Mit der Mühlkreisbahn bis Rottenegg,
von dort entweder abholen lassen oder eine einstündige Wanderung nach Eschelberg: die Straße nach Rottenegg hineingehen, durch den
Ort durch und weiter der Straße den Schildern nach Eschelberg folgen. Bevor es steil den Berg hinaufgeht nach der Brücke über den Eschelbach
links auf den Forstweg abbiegen und in das Eschelbachtal hinein. Nach ca. 1km bei den zweiten Häusern bei denen man vorbei kommt dann rechts
den Berg hinauf. Beim Schloß angelangt einfach die Straße vor gehen, nach 100m bist du am Ziel.<br />
Wer mit der ÖBB nach Linz fährt kauft sich am besten gleich ein Ticket bis nach Rottenegg — da ist schon die Straßenbahn inkludiert
und es ist billiger als 3 einzelne Fahrscheine.
</p>
<p><strong>Auto:</strong> Von Linz auf der B127 Richtung Rohrbach bis Rottenegg, dann den Schildern nach Eschelberg folgen. Unmittelbar nach dem
Ortsteilschild "Eschelberg" in der Spitzkehre links auf den Parkplatz zum Gasthaus Reingruber abfahren. Dort parken und Richtung Schloß
weitergehen.
</p>
<p><strong>Fahrrad:</strong> Von Linz am Donauradweg bis zur Engstelle vor Ottensheim wo die Bundesstraße durch den Tunnel führt, danach dann rechts parallel
zu Bahnstrecke und Bundesstraße auf Radweg/Zufahrststraßen bis zum Bahnhof Rottenegg, dann wie bei der vorigen Beschreibung.
</p>
<h3>Übernachtung</h3>
<p>Es gibt ein paar Zimmer und Matratzen im Haus, weiters Platz im Garten für Zelte sowie einen weiteren großen Raum im Nachbargebäude,
der sich gut für ein Isomattenlager eignet. Schlafsäcke und nach Möglichkeit Unterlagen selbst mitbringen!<br />
Falls jemand mit Kindern anreist, bitte bei einem von uns beiden Gebrüdern im Vorhinein melden, damit wir versuchen können
geeignete Übernachtungsmöglichkeiten zu reservieren.<br />
Wer's komfortabler mag kann sich im <a href="http://gasthof-reingruber.com/">Gasthaus Reingruber</a> nebenan einquartieren.
</p>
<h3>Kontakt</h3>
<p><strong>Veit:</strong> 0681 10276518</p>
<p><strong>Rupert:</strong> 0680 3240381</p>
<p><strong>Festnetz:</strong> 07234 87306</p>
</div>
</body>
About me2019-09-29T09:07:15Zhttps://ngrmr.at/about/<link rel="stylesheet" href="https://ngrmr.at/css/cardboard-box.css" />
<div class="cb">
<main class="cb-box">
<div class="cb-side cb-side--top">
<a href="https://ngrmr.at/" class="cb__home">
<img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" />
<h1 class="visually-hidden">Rupert Angermeier</h1>
</a>
</div>
<div class="cb-side cb-side--front">
<div class="el-stack">
<h2>About me</h2>
<p>Hi, I'm <strong>Rupert Angermeier</strong>. I am, among <a href="https://ngrmr.at/cycling">other things</a>, a software developer, mainly doing web
stuff and in the last years focusing on the frontend.</p>
<p>I've been building websites since the end of the nineties, professionally since 2012. I'm
currently employed at <a href="https://www.trayn.com/">Trayn</a> where I'm reponsible for the web app.</p>
<p>In the last years I worked a lot with JavaScript and CSS, using frameworks and tools like
VueJS, D3js, React, webpack, requireJS, CanJS, LESS, PostCSS and many others.
However, sometimes I prefer to work without any frameworks or pre-processors.
And I know HTML and try to use it an accessible and semantically correct way.</p>
<p>When need arises I also don't shy away from building backends, designing APIs, tinkering with
SQL, configuring web servers and such.</p>
</div>
</div>
<div class="cb-side cb-side--back">
<div class="el-stack">
<h2>Contact & Imprint</h2>
<p>You can find me on <a href="https://github.com/rangermeier">GitHub</a>,
<a href="https://keybase.io/ranger">Keybase</a>,
<a href="https://mastodon.social/@rangermeier">Mastodon</a> or
<a href="https://www.linkedin.com/in/rupert-angermeier-43915b67/">LinkedIn</a>.
You can reach me via e-mail and I also have a postal address, which you can use whenever you
feel the urge to send me physical objects:</p>
<p class="address">
DI Rupert Angermeier<br />
<!--EDV-Dienstleistungen<br>-->
Andreas-Hofer-Straße 11a/5, 1210 Wien, AT<br />
<a class="email">rupert angermeier at gmail</a><br />
<!--UID-Nummer: ATU67163525<br>
Rechtsform: Einzelunternehmer-->
</p>
<h2>Technical Information</h2>
<p>This site is built with <a href="https://www.11ty.dev/">Eleventy</a>.</p>
<p>
It uses the <a href="https://github.com/SorkinType/Alata">Alata</a> and
<a href="http://www.tunera.xyz/fonts/paysage/">Paysage</a> fonts and some
of the layouts described in <a href="https://every-layout.dev/">Every Layout</a>.
</p>
<p>This website does not track or spy on you.</p>
<script type="text/javascript">
var name = document.querySelector("h1").textContent.toLowerCase()
var mail = name.slice(0, 1) + "@ngrmr.at"
document.querySelectorAll("a.email").forEach(function(node) {
node.textContent = mail
node.href = "mailto:"+mail
})
</script>
</div>
</div>
<div class="cb-side cb-side--left">
<span aria-hidden="true" class="no-print cb__home"><img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" /></span>
</div>
<div class="cb-side cb-side--right">
<span aria-hidden="true" class="no-print cb__home"><img src="https://ngrmr.at/assets/logo-with-fonts.svg" class="label" alt="Website Logo, a tilted square labeled Rupert Angermeier - Web Development, HTML, CSS, JS, SVG" /></span>
</div>
<div class="cb-side cb-side--bottom">
<footer class="cb__bottom">
<div class="cb__bottom-text">
<a href="https://ngrmr.at/about">Contact & Imprint</a>
<a href="https://ngrmr.at/feed.rss" rel="alternate" type="application/rss+xml">RSS</a>
<a rel="me" href="https://mastodon.social/@rangermeier">Mastodon</a><br />
<abbr title="Manufacturing Date (last built)">MFD</abbr>
<time datetime="2023-09-07">2023-09-07</time><br />
Best before: Always fresh<br />
</div>
<div class="cb__bottom-barcode" aria-hidden="true">
<img src="https://ngrmr.at/assets/barcode.svg" alt="Barcode which decodes to ngrmr.at" />
</div>
</footer>
</div>
</main>
<div class="cb__controls no-print">
<button class="cb__toggle hidden">Fold Box</button>
<button class="cb__rotate hidden">Rotate</button>
</div>
</div>
<script>
(function() {
var cbBox = document.querySelector('.cb-box')
var btnToggle = document.querySelector('.cb__toggle')
var btnRotate = document.querySelector('.cb__rotate')
if(!cbBox || !btnToggle) {
return
}
btnToggle.classList.remove('hidden')
btnToggle.addEventListener('click', function() {
cbBox.classList.toggle('cb-box--folded')
var isFolded = cbBox.classList.contains('cb-box--folded')
cbBox.classList.toggle('cb-box--unfolded', !isFolded)
btnToggle.innerHTML = isFolded ? 'Unfold Box' : 'Fold Box'
btnRotate.classList.toggle('hidden', !isFolded)
btnRotate.innerHTML = 'Rotate'
if(isFolded) {
window.scrollTo(0, 0)
} else {
cbBox.classList.toggle('cb-box--rotating', false)
cbBox.classList.toggle('cb-box--rotate-pause', false)
}
})
btnRotate.addEventListener('click', function() {
var isRotating = cbBox.classList.contains('cb-box--rotating')
if(isRotating) {
cbBox.classList.toggle('cb-box--rotate-pause')
} else {
cbBox.classList.toggle('cb-box--rotating')
}
btnRotate.innerHTML = isRotating ? 'Rotate' : 'Pause'
})
}())
</script>