<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/feeds/stylesheet.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	
	
	<link href="https://blog.comandeer.pl/feeds/feed.xml" rel="self" type="application/atom+xml"/>
	<link href="https://blog.comandeer.pl/" rel="alternate" type="text/html"/>
	<updated>2026-04-25T11:06:04.890Z</updated>
	<id>https://blog.comandeer.pl/feeds/feed.xml</id>
	<title type="html">Comandeerowy blog</title>
	
		<subtitle>Kolejny nudny blog kolejnego nudnego fanatyka JS-a. Nie czytać, nie warto tracić czasu.</subtitle>
	
	
		
	
	
		<entry>
			<title type="html">CSS Naked Day 2026</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/css-naked-day-2026" rel="alternate" type="text/html"/>
			<published>2026-04-08T23:06:00.000Z</published>
			<updated>2026-04-08T23:06:00.000Z</updated>
			<id>https://blog.comandeer.pl/css-naked-day-2026</id>
			
				<summary><![CDATA[Świętujmy razem CSS Naked Day 2026 🎉!]]></summary>
			
			<content type="html"><![CDATA[<p>Ale ten czas leci. Mamy nowy rok a wraz z nim – nowy <a href="https://css-naked-day.org/" rel="noreferrer noopener">CSS Naked Day</a>! To ten jeden dzień w roku, w którym skupiamy się na pięknie semantycznego HTML-a zamiast na wizualiach. A żeby móc w pełni podziwiać HTML-a, CSS na ten jeden dzień znika. Przy okazji jak na dłoni widać wszystkie HTML-owe niedoróbki.</p>
<p>Miłego świętowania 🎉!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Piękno reklam</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/piekno-reklam" rel="alternate" type="text/html"/>
			<published>2026-04-01T16:39:00.000Z</published>
			<updated>2026-04-01T16:39:00.000Z</updated>
			<id>https://blog.comandeer.pl/piekno-reklam</id>
			
				<summary><![CDATA[Dodaję reklamy na bloga]]></summary>
			
			<content type="html"><![CDATA[<p>Podjąłem decyzję – na blogu pojawią się reklamy!</p>
<p><ad-></ad-></p>
<p>Postanowiłem, ze nadeszła pora, by zmonetyzować swoją wiedzę. Przez wszystkie te lata dzieliłem się nią za darmo, ale być może w końcu nadszedł czas, by to zmienić.</p>
<p><ad-></ad-></p>
<p>Zadbałem o to, by reklamy nie były zbyt agresywne. Dzięki temu są dopasowane do treści i nie przeszkadzają za bardzo przy zapoznawaniu się z nią.</p>
<p><ad-></ad-></p>
<p><ad-></ad-></p>
<p>Również bloki kodu doczekały się własnych reklam:</p>
<code-ad>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">TypeScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isNumber</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> unknown</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#E36209;--shiki-dark:#FFAB70"> value</span><span style="color:#D73A49;--shiki-dark:#F97583"> is</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> number</span><span style="color:#D73A49;--shiki-dark:#F97583"> =&gt;</span><span style="color:#D73A49;--shiki-dark:#F97583"> typeof</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> value </span><span style="color:#D73A49;--shiki-dark:#F97583">===</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'number'</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isEven</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> unknown</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> boolean</span><span style="color:#D73A49;--shiki-dark:#F97583"> =&gt;</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isNumber</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(value) </span><span style="color:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> value </span><span style="color:#D73A49;--shiki-dark:#F97583">%</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 2</span><span style="color:#D73A49;--shiki-dark:#F97583"> ===</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> 0</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isOdd</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> unknown</span><span style="color:#24292E;--shiki-dark:#E1E4E8">)</span><span style="color:#D73A49;--shiki-dark:#F97583">:</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> boolean</span><span style="color:#D73A49;--shiki-dark:#F97583"> =&gt;</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> isNumber</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(value) </span><span style="color:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="color:#D73A49;--shiki-dark:#F97583"> !</span><span style="color:#6F42C1;--shiki-dark:#B392F0">isEven</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(value)</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure></code-ad>
<p>Mam nadzieję, że ta mała, nieinwazyjna zmiana się spodoba!</p>
<p><ad-></ad-></p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Piękno prezentacji</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/piekno-prezentacji" rel="alternate" type="text/html"/>
			<published>2026-03-21T21:53:00.000Z</published>
			<updated>2026-03-21T21:53:00.000Z</updated>
			<id>https://blog.comandeer.pl/piekno-prezentacji</id>
			
				<summary><![CDATA[Opublikowałem swoją prezentację o inkluzywnym designie z Warsaw IT Days]]></summary>
			
			<content type="html"><![CDATA[<p>19 marca miałem okazję poopowiadać o respektowaniu preferencji osoby odwiedzającej stronę&nbsp;WWW na  <a href="https://warszawskiedniinformatyki.pl/" rel="noreferrer noopener">Warsaw IT Days</a>. Jeśli ktoś chcialby sobie przypomnieć moją <a href="https://blog.comandeer.pl/assets/piekno-prezentacji/wid-2026.pdf"><em>jakże piękną i wspaniałą</em> prezentację</a>, to od teraz jest dostępna na tym blogu.</p>
<p>Dzięki za dołączenie online, żeby posłuchać!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Warsaw IT Days 2026 – kod rabatowy</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/wdi-2026-kod-rabatowy" rel="alternate" type="text/html"/>
			<published>2026-03-09T21:38:00.000Z</published>
			<updated>2026-03-09T21:38:00.000Z</updated>
			<id>https://blog.comandeer.pl/wdi-2026-kod-rabatowy</id>
			
				<summary><![CDATA[Zniżka na Warsaw IT Days 2026 tylko dla osób czytających mojego bloga!]]></summary>
			
			<content type="html"><![CDATA[<p>Już wkrótce kolejna edycja <a href="https://warszawskiedniinformatyki.pl/" rel="noreferrer noopener">Warsaw IT Days</a> – 19 marca widzimy się online, a 20 marca kolejne prelekcje odbędą się na PGE Narodowym w Warszawie. Oprócz mojego wystąpienia będzie można posłuchać ponad 300 innych na 25 ścieżkach tematycznych.</p>
<p>Dla osób czytających mojego bloga mam kod rabatowy, dzięki któremu można kupić bilety w pakietach Standard i Exec o 20% taniej. Kod rabatowy to: <strong>WID26SP20</strong>. Można go użyć w trakcie <a href="https://warszawskiedniinformatyki.pl/registration.html" rel="noreferrer noopener">kupowania biletu na oficjalnej stronie wydarzenia</a>.</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Piękno CSS-a</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/piekno-cssa" rel="alternate" type="text/html"/>
			<published>2026-03-05T21:57:00.000Z</published>
			<updated>2026-03-05T21:57:00.000Z</updated>
			<id>https://blog.comandeer.pl/piekno-cssa</id>
			
				<summary><![CDATA[Opublikowałem swoją prezentację o CSS-ie z OLX Frontend Masterclass]]></summary>
			
			<content type="html"><![CDATA[<p>3 marca miałem okazję wygłosić prelekcję na wydarzeniu <a href="https://evenea.pl/pl/wydarzenie/masterclassfrontend" rel="noreferrer noopener">OLX Frontend Masterclass</a> w Poznaniu. Opowiadałem tam o nowych ficzerach w CSS-ie. <em>Przepiękne</em> demo z tej prezentacji <a href="https://github.com/Comandeer/cssdemo" rel="noreferrer noopener">wrzuciłem już na GitHuba</a>. Z kolei <a href="https://www.youtube.com/watch?v=Mcqm15d-qmI" rel="noreferrer noopener">zapis streama z wydarzenia</a> jest dostępny na YouTube.</p>
<p>Dzięki za wpadnięcie, żeby posłuchać, i dzięki za ciekawe dyskusje w trakcie networkingu!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Prelekcjowy marzec</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/prelekcjowy-marzec" rel="alternate" type="text/html"/>
			<published>2026-02-20T21:29:00.000Z</published>
			<updated>2026-02-20T21:29:00.000Z</updated>
			<id>https://blog.comandeer.pl/prelekcjowy-marzec</id>
			
				<summary><![CDATA[W marcu 2026 będzie mnie można usłyszeć na aż dwóch wydarzeniach: OLX Masterclass Frontend oraz Warsaw IT Days!]]></summary>
			
			<content type="html"><![CDATA[<p>Marzec zapowiada się niezwykle pracowicie, bo wygłoszę w nim aż dwie prelekcje – i to na dwa zupełnie różne tematy!</p>
<h2 id="olx-masterclass-frontend"><a class="header-anchor" href="https://blog.comandeer.pl/prelekcjowy-marzec#olx-masterclass-frontend">OLX Masterclass Frontend</a></h2>
<p><strong>3 marca 2026 o godzinie 18:00</strong> rozpocznie się <a href="https://evenea.pl/pl/wydarzenie/masterclassfrontend" rel="noreferrer noopener">OLX Masterclass Frontend</a>. Można w nim uczestniczyć zarówno fizycznie, w <a href="https://maps.app.goo.gl/A6K6svPFJfkEbTD67" rel="noreferrer noopener">poznańskim biurze OLX</a>, jak i <a href="https://docs.google.com/forms/d/e/1FAIpQLSeAFoynaDeryxixlrYik4RJScBwKjh9ybqe5-GL6xrxrfXPIQ/viewform" rel="noreferrer noopener">dołączyć online</a>. Wstęp na wydarzenie jest darmowy. Usłyszeć&nbsp;będzie można trzy prelekcje o tematyce webdevowej. Ja opowiadać będę o zmianach, jakie zaszły w nowoczesnym CSS-ie – w tym zagnieżdżaniu, warstwach czy regule <code>@scope</code> – oraz o tym, jak mogą one wpłynąć na to, jak piszemy i zarządzamy stylami. Dla transparentności: za tę prelekcję <strong>pobieram wynagrodzenie</strong>. Po wszystkim będzie można się napić kawy i pogadać.</p>
<h2 id="warsaw-it-days-2026"><a class="header-anchor" href="https://blog.comandeer.pl/prelekcjowy-marzec#warsaw-it-days-2026">Warsaw IT Days 2026</a></h2>
<p>Z kolei <strong>19 marca 2026</strong> (online) i <strong>20 marca 2026</strong> (na <a href="https://maps.app.goo.gl/5UnHbp2A3MkXbmMZ9" rel="noreferrer noopener">PGE Narodowym w Warszawie</a>) odbywa się kolejna edycja <a href="https://warszawskiedniinformatyki.pl/" rel="noreferrer noopener">Warsaw IT Days</a>. Można posłuchać ponad 300 prelekcji na 25 różnych ścieżkach tematycznych.</p>
<p><picture><source type="image/avif" srcset="/assets/images/prelekcyjny-marzec/wdi-440w.avif 440w, /assets/images/prelekcyjny-marzec/wdi-880w.avif 880w, /assets/images/prelekcyjny-marzec/wdi-1024w.avif 1024w" sizes="90vw"><source type="image/webp" srcset="/assets/images/prelekcyjny-marzec/wdi-440w.webp 440w, /assets/images/prelekcyjny-marzec/wdi-880w.webp 880w, /assets/images/prelekcyjny-marzec/wdi-1024w.webp 1024w" sizes="90vw"><source type="image/png" srcset="/assets/images/prelekcyjny-marzec/wdi-440w.png 440w, /assets/images/prelekcyjny-marzec/wdi-880w.png 880w, /assets/images/prelekcyjny-marzec/wdi-1024w.png 1024w" sizes="90vw"><img src="/assets/images/prelekcyjny-marzec/wdi-1024w.png" width="1024" height="1024" style="aspect-ratio: 1024 / 1024" alt="" loading="lazy" decoding="async"></picture></p>
<p>Moje wystąpienie, <cite lang="en">Giving control back to the user</cite>, będzie transmitowane online <strong>19 marca 2026 o 14:35</strong>. Będę mówił o inkluzywnym designie, a dokładniej – o respektowaniu preferencji osób korzystających z naszej strony WWW. <a href="https://warszawskiedniinformatyki.pl/registration.html" rel="noreferrer noopener">Bilety można kupić&nbsp;na stronie wydarzenia</a>.</p>
<p>Obydwa wystąpienia będą w całości po angielsku. Serdecznie zapraszam!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Sadząc drzewa</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/sadzac-drzewa" rel="alternate" type="text/html"/>
			<published>2026-01-31T22:06:00.000Z</published>
			<updated>2026-01-31T22:06:00.000Z</updated>
			<id>https://blog.comandeer.pl/sadzac-drzewa</id>
			
				<summary><![CDATA[Narzędzia pozwalają wypluwać przy pomocy JSX-a różne typy drzewek, nie tylko Reactowe. W tym wpisie przyglądam się, jak to zrobić.]]></summary>
			
			<content type="html"><![CDATA[<p>Dawno, dawno temu pokazywałem, jak przygotować <a href="https://blog.comandeer.pl/prymitywna-implementacja-mitycznej-funkcji-react-createelement">własną wersję funkcji <code>React.createElement()</code></a>. Jednak nic więcej z nią nie zrobiliśmy. A przecież możemy ją wykorzystać w JSX-ie!</p>
<h2 id="jsx"><a class="header-anchor" href="https://blog.comandeer.pl/sadzac-drzewa#jsx">JSX</a></h2>
<p>Wypada jednak na samym początku wspomnieć, czym w ogóle jest JSX. Za <a href="https://facebook.github.io/jsx/" rel="noreferrer noopener">oficjalną&nbsp;dokumentacją</a>:</p>
<blockquote>
<p lang="en">JSX is an XML-like syntax extension to ECMAScript without any defined semantics. […] It's intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.</p>
<p>[JSX to rozszerzenie składni ECMAScript o składnię podobną do XML-a bez definiowania konkretnej semantyki. […] Jest przeznaczone do użytku przez różnego rodzaju preprocesory (transpilery) do transformacji tych tokenów w standardową składnię ECMAScriptu.]</p>
</blockquote>
<p>Przekładając to na ludzki – JSX pozwala umieszczać w kodzie JS coś, co <em>wygląda</em> jak kod XML:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSX</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">article</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">h1</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;Hello, world!&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">h1</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">p</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;Some content&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">p</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">article</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;;</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Niemniej kod w takiej postaci nie ma być rozumiany przez przeglądarki czy środowiska uruchomieniowe typu Node.js. Taki kod powinien być najpierw przepuszczony przez jakieś narzędzie (transpiler), które przetłumaczy go na zwyczajny kod JS. Praktycznie każdy szanujący się&nbsp;transpiler JS-a ma wsparcie dla JSX-a (np. <a href="https://www.typescriptlang.org/docs/handbook/jsx.html" rel="noreferrer noopener">TypeScript ma wbudowane</a>, a <a href="https://babeljs.io/docs/babel-plugin-transform-react-jsx" rel="noreferrer noopener">Babel potrzebuje pluginu</a>). Jeśli przepuścimy przez jeden z nich powyższy kod, powinniśmy otrzymać coś takiego:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> React.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">createElement</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'article'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">null</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	React.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">createElement</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'h1'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">null</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'Hello, world!'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ), </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 2</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	React.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">createElement</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'p'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">null</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'Some content'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 3</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Każdy z XML-owych elementów w naszym JSX-ie został zamieniony na wywołanie funkcji <code>React.createElement()</code>. Jest też oddana relacja między poszczególnymi elementami – wywołania dla <code>h1</code> (2) i <code>p</code> (3) znajdują się wewnątrz wywołania dla <code>article</code> (1). Dzięki temu React jest w stanie odtworzyć w swoim vDOM-ie dokładnie takie drzewko, jakie zaprojektowaliśmy w JSX-ie.</p>
<div class="note" role="note" aria-labelledby="note-48"><p class="note__label" id="note-48">Dygresja</p><div class="note__content"><p>Dokładniejszy opis tej funkcji znajduje się w przywołanym już we wstępie <a href="https://blog.comandeer.pl/prymitywna-implementacja-mitycznej-funkcji-react-createelement">artykule o tworzeniu własnej wersji funkcji <code>React.createElement()</code></a>.</p></div></div>
<h2 id="wykorzystanie-własnej-funkcji"><a class="header-anchor" href="https://blog.comandeer.pl/sadzac-drzewa#wykorzystanie-własnej-funkcji">Wykorzystanie własnej funkcji</a></h2>
<p>Domyślnie JSX jest zawsze tłumaczony do wywołań funkcji <code>React.createElement()</code>. A co jeśli nie chcemy korzystać&nbsp;z Reacta? Wówczas mamy dwie możliwości podmiany tej funkcji.</p>
<p>Pierwsza z nich, mniej elegancka, to… stworzenie funkcji <code>React.createElement()</code>:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> React</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">	createElement</span><span style="color:#24292E;--shiki-dark:#E1E4E8">() {</span></span>
<span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D">		// Tutaj jakiś kod</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">};</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Niemniej istnieje też bardziej elegancka metoda: <em>nadpisanie semantyki JSX-a</em>. Czyli powiedzenie naszemu transpilerowi, jak dokładnie ma transformować kod JSX. Minusem tej metody jest różnica w konfiguracji poszczególnych narzędzi. W przypadku jednak tych najpopularniejszych (TypeScript, Babel, <a href="https://esbuild.github.io/api/#jsx-factory" rel="noreferrer noopener">esbuild</a>) można wykorzystać <a href="https://www.johno.com/jsx-pragma" rel="noreferrer noopener">pragmę</a> – czyli komentarz wskazujący odpowiednią funkcję:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSX</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D">/* @jsx myFunction */</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">article</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">h1</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;Hello, world!&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">h1</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">p</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;Some content&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">p</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">article</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;;</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>W tym przypadku informujemy transpiler, że ma używać funkcji o nazwie <code>myFunction()</code>. Dzięki temu po transpilacji dostaniemy następujący kod:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D">/* @jsx myFunction */</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> myFunction</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'article'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">null</span><span style="color:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">	myFunction</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'h1'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">null</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'Hello, world!'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ),</span></span>
<span class="line"><span style="color:#6F42C1;--shiki-dark:#B392F0">	myFunction</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'p'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#005CC5;--shiki-dark:#79B8FF">null</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'Some content'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> )</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Dzięki temu możemy podstawić naszą&nbsp;implementację <code>React.createElement()</code>, która czekała na ten moment <em>niemalże 9 lat</em>:</p>
<div><embed- src="https://codepen.io/Comandeer/pen/NPrYRaw"><p class="embed-fallback"><a href="https://codepen.io/Comandeer/pen/NPrYRaw" rel="noreferrer noopener">Przejdź bezpośrednio do osadzonej treści na CodePenie.</a></p></embed-></div>
<div class="note" role="note" aria-labelledby="note-49"><p class="note__label" id="note-49">Dygresja</p><div class="note__content"><p><a href="https://blog.codepen.io/documentation/es-modules-on-codepen/#react-and-jsx" rel="noreferrer noopener">CodePen pozwala używać Babela</a> do pisania JS-a, dzięki czemu działa na nim JSX.</p></div></div>
<p>Ale wypluwanie elementów HTML z JSX-a jest <em>nudne</em>. Tak naprawdę można generować absolutnie wszystko, co da się&nbsp;zapisać jako drzewko elementów. Jak np. tekstowe drzewko plików:</p>
<div><embed- src="https://codepen.io/Comandeer/pen/JoKLRyg"><p class="embed-fallback"><a href="https://codepen.io/Comandeer/pen/JoKLRyg" rel="noreferrer noopener">Przejdź bezpośrednio do osadzonej treści na CodePenie.</a></p></embed-></div>
<p>W tym przypadku funkcja obsługująca JSX wygląda następująco:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">function</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> jsx</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#E36209;--shiki-dark:#FFAB70">tag</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#E36209;--shiki-dark:#FFAB70">attributes</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#D73A49;--shiki-dark:#F97583">...</span><span style="color:#E36209;--shiki-dark:#FFAB70">children</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	const</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> { </span><span style="color:#005CC5;--shiki-dark:#79B8FF">name</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> } </span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> attributes; </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> childrenContent</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> children.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">map</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( ( </span><span style="color:#E36209;--shiki-dark:#FFAB70">child</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) </span><span style="color:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		return</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> `${</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> child</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }`</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">			.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">replaceAll</span><span style="color:#24292E;--shiki-dark:#E1E4E8">(</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> /</span><span style="color:#D73A49;--shiki-dark:#F97583">^</span><span style="color:#032F62;--shiki-dark:#9ECBFF">/</span><span style="color:#D73A49;--shiki-dark:#F97583">gm</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\n</span><span style="color:#032F62;--shiki-dark:#9ECBFF">|   '</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 3</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">			.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">replaceAll</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\n\n</span><span style="color:#032F62;--shiki-dark:#9ECBFF">'</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'</span><span style="color:#005CC5;--shiki-dark:#79B8FF">\n</span><span style="color:#032F62;--shiki-dark:#9ECBFF">'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	} ).</span><span style="color:#6F42C1;--shiki-dark:#B392F0">join</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#032F62;--shiki-dark:#9ECBFF">''</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 4</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	return</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> `| - ${</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> name</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }${</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> childrenContent</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> }`</span><span style="color:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Z JSX-owego elementu pobieramy atrybut <code>name</code> (1) – to nazwa katalogu lub pliku. Zwracamy ją&nbsp;(2) jako ciąg tekstowy razem z fajką (<code>|</code>), wskazującą aktualny poziom zagłębienia, oraz ciągami tekstowymi zwróconymi przez dzieci. Te nieco modyfikujemy, dodając do każdego pliku/katalogu brakujące fajki (3), a następnie łącząc wszystkie dzieci w jeden duży ciąg tekstowy (4).</p>
<p>Natomiast JSX użyty do tego przykładu wygląda następująco:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSX</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#6A737D;--shiki-dark:#6A737D">/* @jsx jsx */</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">directory</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> name</span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"/"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">file</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> name</span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"README.md"</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> /&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">directory</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> name</span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"src/"</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		&lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">file</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> name</span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"index.ts"</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> /&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">directory</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">directory</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;;</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><h2 id="komponenty"><a class="header-anchor" href="https://blog.comandeer.pl/sadzac-drzewa#komponenty">Komponenty</a></h2>
<p>Niemniej w JSX-ie oprócz zwyczajnych elementów istnieją również komponenty, a więc elementy, których nazwy zaczynają&nbsp;się wielką literą. Spójrzmy na taki przykład:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JSX</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &lt;</span><span style="color:#005CC5;--shiki-dark:#79B8FF">Greeting</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> name</span><span style="color:#D73A49;--shiki-dark:#F97583">=</span><span style="color:#032F62;--shiki-dark:#9ECBFF">"Comandeer"</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> /&gt;;</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Jeśli przepuścimy ten kod przez transpiler, otrzymamy mniej więcej coś takiego:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> component</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> React.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">createElement</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( Greeting, { name: </span><span style="color:#032F62;--shiki-dark:#9ECBFF">'Comandeer'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> } );</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>W tym przypadku do <code>React.createElement()</code> jako pierwszy argument nie jest przekazywana nazwa elementu, ale referencja do <code>Greeting</code>. Wypada zatem stworzyć taką funkcję:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">function</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> Greeting</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( { </span><span style="color:#E36209;--shiki-dark:#FFAB70">name</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> } ) { </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	return</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> &lt;</span><span style="color:#22863A;--shiki-dark:#85E89D">h1</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;Hello, {name}!&lt;/</span><span style="color:#22863A;--shiki-dark:#85E89D">h1</span><span style="color:#24292E;--shiki-dark:#E1E4E8">&gt;; </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 2</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Jako parametr przyjmuje ona obiekt z atrybutami (1), z którego wyciągamy atrybut <code>name</code>. Następnie zwracamy element <code>h1</code>, wewnątrz którego wykorzystujemy ten atrybut do stworzenia powitania (2).</p>
<p>Wypada nieco zmodyfikować naszą funkcję do obsługi JSX-a:</p>
<figure class="code" typeof="SoftwareSourceCode">
			<figcaption class="code__caption">
				<span class="code__title" property="programmingLanguage">JavaScript</span>
				
			</figcaption>
			<div class="code__code" translate="no" property="text">
				<pre class="shiki shiki-themes github-light github-dark" style="background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8" tabindex="0"><code><span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">function</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> jsx</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( </span><span style="color:#E36209;--shiki-dark:#FFAB70">tag</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#E36209;--shiki-dark:#FFAB70">attributes</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#D73A49;--shiki-dark:#F97583">...</span><span style="color:#E36209;--shiki-dark:#FFAB70">children</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( </span><span style="color:#D73A49;--shiki-dark:#F97583">typeof</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> tag </span><span style="color:#D73A49;--shiki-dark:#F97583">===</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'function'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) { </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 1</span></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">		return</span><span style="color:#6F42C1;--shiki-dark:#B392F0"> tag</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( { </span><span style="color:#D73A49;--shiki-dark:#F97583">...</span><span style="color:#24292E;--shiki-dark:#E1E4E8">attributes, children } ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 2</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	const</span><span style="color:#005CC5;--shiki-dark:#79B8FF"> element</span><span style="color:#D73A49;--shiki-dark:#F97583"> =</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> document.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">createElement</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( tag );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	if</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ( attributes </span><span style="color:#D73A49;--shiki-dark:#F97583">&amp;&amp;</span><span style="color:#D73A49;--shiki-dark:#F97583"> typeof</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> attributes </span><span style="color:#D73A49;--shiki-dark:#F97583">===</span><span style="color:#032F62;--shiki-dark:#9ECBFF"> 'object'</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		Object.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">entries</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( attributes ).</span><span style="color:#6F42C1;--shiki-dark:#B392F0">forEach</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( ( [ </span><span style="color:#E36209;--shiki-dark:#FFAB70">name</span><span style="color:#24292E;--shiki-dark:#E1E4E8">, </span><span style="color:#E36209;--shiki-dark:#FFAB70">value</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ] ) </span><span style="color:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">			element.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">setAttribute</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( name, value );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		} );</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	children.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">forEach</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( ( </span><span style="color:#E36209;--shiki-dark:#FFAB70">child</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> ) </span><span style="color:#D73A49;--shiki-dark:#F97583">=&gt;</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">		element.</span><span style="color:#6F42C1;--shiki-dark:#B392F0">append</span><span style="color:#24292E;--shiki-dark:#E1E4E8">( child ); </span><span style="color:#6A737D;--shiki-dark:#6A737D">// 3</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">	} );</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;--shiki-dark:#F97583">	return</span><span style="color:#24292E;--shiki-dark:#E1E4E8"> element;</span></span>
<span class="line"><span style="color:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"></span></code></pre>

			</div>
		</figure><p>Większość logiki została taka sama, pojawił się jedynie dodatkowy warunek na początku. Sprawdza on, czy przekazany <code>tag</code> jest funkcją&nbsp;(1) i jeśli tak, to wywołuje ją, przekazując jako parametr obiekt zawierający atrybuty oraz własność <code>children</code> z dziećmi (2). Robimy to w taki sposób, żeby zachować Reactowy kształt API. Przy okazji, dzięki użyciu <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/append" rel="noreferrer noopener">metody <code>#append()</code></a> (3) przy dodawaniu dzieci zniknęła potrzeba tworzenia węzła tekstowego. Metoda <code>#append()</code> bowiem, w przeciwieństwie do starszej <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild" rel="noreferrer noopener">metody <code>#appendChild()</code></a>, pozwala dodawać tekst bezpośrednio do elementu.</p>
<p>Nasza obsługa komponentów prezentuje się następująco:</p>
<div><embed- src="https://codepen.io/Comandeer/pen/ogLqBPm"><p class="embed-fallback"><a href="https://codepen.io/Comandeer/pen/ogLqBPm" rel="noreferrer noopener">Przejdź bezpośrednio do osadzonej treści na CodePenie.</a></p></embed-></div>
<p>I tak oto udało nam się przygotować własną, prostą obsługę JSX-a! Oczywiście, nie jest ona skończona, brakuje choćby sensownej obsługi <a href="https://react.dev/reference/react/Fragment" rel="noreferrer noopener">fragmentów</a>. Niemniej jest fajnym punktem wyjścia do dalszych eksperymentów.</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Podsumowanie 2025</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/podsumowanie-2025" rel="alternate" type="text/html"/>
			<published>2025-12-31T22:15:00.000Z</published>
			<updated>2025-12-31T22:15:00.000Z</updated>
			<id>https://blog.comandeer.pl/podsumowanie-2025</id>
			
				<summary><![CDATA[Krótko o tym, co się wydarzyło w 2025 roku]]></summary>
			
			<content type="html"><![CDATA[<p>Kolejny rok minął… Nie powiem, był męczący i mało produktywny. A potem wpadłem na <em>iście genialny</em> pomysł i stwierdziłem, że zrobię <a href="https://blog.comandeer.pl/kategorie/adwent-2025/">kalendarz adwentowy</a>. I jakimś cudem dowiozłem! Mimo że byłem pewien, że się nie uda. 19 grudnia złapało mnie choróbsko i kalendarz był zagrożony, ale udało mi zebrać się do kupy i opublikować kolejny wpis 20 grudnia (co prawda o 17, zamiast o północy, ale hej – i tak się liczy!). Tym samym norma na blogu została wyrobiona – i to podwójnie! Ale jeśli ktoś się&nbsp;zastanawia, czy w przyszłym roku też będzie kalendarz adwentowy: nie, na pewno nie. Będzie za to <em>wieniec</em> adwentowy, czyli jeden wpis na każdą niedzielę adwentu.</p>
<p>Jeśli chodzi o rzeczy, z których jestem dumny: na tym blogu to zdecydowanie tekst <a href="https://blog.comandeer.pl/nullius-in-verba"><cite lang="la">Nullius in verba</cite></a> oraz <a href="https://blog.comandeer.pl/projekty/czasomierze/">projekt czasomierzy</a>. I tak, zdaję sobie sprawę, że jest ukończony gdzieś w połowie, ale styczeń i luty brzmią jak dobry czas, by go dokończyć. I ruszyć w końcu z kolejnym zapowiedzianym projektem, czyli <a href="https://blog.comandeer.pl/projekty/doco/">Doco</a>! Bo nie będę ukrywał, moje projekty w tym roku leżały odłogiem i nie miałem sił do nich zaglądnąć. Ale kalendarz trochę mnie rozruszał. A bardzo mi się to przyda, bo oprócz projektów jest przecież również WebKrytyk, który ostatnio też trochę się zakurzył. W tym roku pojawiły się na nim raptem 4 teksty, z których najbardziej podoba mi się ten o <a href="https://www.webkrytyk.pl/2025/05/15/wpadki-i-wypadki-20/" rel="noreferrer noopener">odpowiadających sobie doświadczeniach</a>. Nie można też pominąć faktu, że… <a href="https://www.webkrytyk.pl/2025/12/31/100-lat-czyli-sentymentalna-podroz-w-przeszlosc/#15-lat-minelo" rel="noreferrer noopener">WebKrytyk ma już 15 lat</a>. Yay…!</p>
<p>I to w sumie tyle. Szczęśliwego Nowego Roku 🍾!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Nullius in verba</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/nullius-in-verba" rel="alternate" type="text/html"/>
			<published>2025-12-23T23:06:00.000Z</published>
			<updated>2025-12-23T23:06:00.000Z</updated>
			<id>https://blog.comandeer.pl/nullius-in-verba</id>
			
				<summary><![CDATA[A co, gdybyśmy traktowali webdev bardziej jak naukę?]]></summary>
			
			<content type="html"><![CDATA[<p>Osoby nieco dłużej śledzące moją internetową aktywność mogły zauważyć pewną zmianę mojego podejścia do tematów webdevowych. W mojej dawnej webkrytykowej twórczości, ale i w początkach istnienia tego bloga, o wiele więcej było, hm, <em>emocjonalnych</em> wstawek. Niczym dekadencki poeta z bujną i rozwichrzoną czupryną zdecydowanie stawiałem formę wyżej od treści. Obecnie moje podejście jest zdecydowanie bardziej <em>naukowe</em>. I to bynajmniej nie z powodu nagłego braku bujnej czupryny!</p>
<h2 id="podejście-naukowe"><a class="header-anchor" href="https://blog.comandeer.pl/nullius-in-verba#podejście-naukowe">Podejście naukowe</a></h2>
<p>Co to jednak znaczy, że traktuję webdev naukowo? Tak naprawdę wyróżniłbym tutaj trzy główne elementy:</p>
<ol>
<li>formę treści,</li>
<li>obecność źródeł,</li>
<li>empiryczność.</li>
</ol>
<h3 id="forma-treści"><a class="header-anchor" href="https://blog.comandeer.pl/nullius-in-verba#forma-treści">Forma treści</a></h3>
<p>Artykuły naukowe mają ściśle określoną strukturę. Bardzo często opisuje się ją <a href="https://en.wikipedia.org/wiki/IMRAD" rel="noreferrer noopener">akronimem IMRaD</a>:</p>
<ol>
<li><b lang="en">Introduction</b> (wprowadzenie) – wyjaśnienie celu badania, postawienie hipotezy,</li>
<li><b lang="en">Methods</b> (metody badawcze) – w jaki sposób badanie zostało wykonane, kto w nim uczestniczył,</li>
<li><b lang="en">Results</b> (wyniki) – omówienie wyników badania, sprawdzenie, czy wyniki zgadzają się&nbsp;z postawioną hipotezą,</li>
<li><b lang="en">Discussion</b> (polemika) – próba interpretacji wyników, porównanie ich z innymi badaniami z tego zakresu, zaproponowanie możliwych przyszłych kierunków badań.</li>
</ol>
<p>Tak tworzone artykuły powinny zachowywać jak największą obiektywność, skupiając się przede wszystkim na opisie faktów, z pominięciem opinii osób autorskich.</p>
<p>Ja nie jestem naukowcem i siłą mojego bloga jest jednak to, że umieszczam na nim materiały o webdevie okraszone <em>moją</em> opinią. Więc bardziej nazwałbym swoją radosną twórczość <dfn id="esej-hipertekstowy">esejami hipertekstowymi</dfn>. To nic innego jak <a href="https://pl.wikipedia.org/wiki/Esej" rel="noreferrer noopener">eseje</a>, które są opublikowane w formie hipertekstu. Czyli: mogą linkować do innych esejów lub bezpośrednio do źródeł, Równocześnie jednak – raz luźniej, raz ściślej – trzymam się struktury IMRaD. Weźmy taki <a href="https://blog.comandeer.pl/pudelko-z-ciasteczkami">artykuł o Cookie Store API</a>. Na samym początku jest wprowadzenie, w którym zaznaczam problem (<q>relacja Sieci z ciasteczkami od zawsze była skomplikowana</q>). Następnie następuje omówienie wyników badania (w tym wypadku: organoleptycznego sprawdzenia, jak się obsługuje ciasteczka w przeglądarkach). W przypadku artykułów z eksperymentów (jak np. <a href="https://blog.comandeer.pl/jednoplikowe-komponenty">jednoplikowych komponentów</a> czy <a href="https://blog.comandeer.pl/ascss">ASCSS-a</a>) pojawiają się&nbsp;też sekcje z metodami (opis inspiracji i narzędzi użytych do stworzenia danego projektu) oraz polemika (w jaki sposób go dalej rozwijać, czy moje pierwotne założenia udało się spełnić, itd.).</p>
<h3 id="źródła"><a class="header-anchor" href="https://blog.comandeer.pl/nullius-in-verba#źródła">Źródła</a></h3>
<p>Niemniej to nie forma jest głównym wyznacznikiem “naukowości”. Według mnie o wiele ważniejszym jest odwoływanie się do źródeł. W końcu szansa, że opisałem coś jako pierwszy w Internecie, jest niemalże zerowa. Nawet jeśli w swoim zakątku Sieci jestem faktycznie pierwszy, to przecież o jakimś standardzie sieciowym napisała przede mną choćby… osoba pisząca jego specyfikację. Nawet jeśli już wymyślę&nbsp;coś absolutnie swojego (jak <a href="https://blog.comandeer.pl/headings-first-principle"><span lang="en">Headings First Principle</span> (HFP)</a>), to przecież to nie istnieje w próżni. Żeby mogło powstać HFP, musiał powstać HTML, a w nim nagłówki. Niezbędnymi elementami były też wszelkie <a href="https://www.smashingmagazine.com/2022/07/article-section-elements-accessibility/" rel="noreferrer noopener">dobre praktyki wokół dzielenia treści stron WWW na sekcje</a> oraz <a href="https://webaim.org/projects/screenreadersurvey10/#finding" rel="noreferrer noopener">sposób nawigowania przy pomocy nagłówków przez osoby korzystające z czytników ekranowych</a>. Słowem: musiał istnieć cały skomplikowany ekosystem Sieci, żebym ja mógł do niego dodać swoją małą&nbsp;cegiełkę.</p>
<p>Chyba najdobitniej widać to w przypadku mojego, jak dotąd najambitniejszego, projektu, <a href="https://gwd.comandeer.pl/" rel="noreferrer noopener">GWD</a>. W każdym “rozdziale” na końcu znajdują&nbsp;się listy źródeł oraz dodatkowych materiałów. Nazbierało się ich <strong>około tysiąca</strong>. A i tak była to mocno okrojona lista. Zwłaszcza, że sporo tematów ostatecznie wypadło z tego eseju.</p>
<p>Niemniej samo odesłanie do źródeł to za mało. Prawdziwa praca polega na odpowiednim ich dobraniu. Bo można opisać np. element HTML <code>bdo</code> i odesłać do jakiejś strony-krzak czy <a href="https://www.webkrytyk.pl/2022/10/30/w3schools-com-runda-druga/" rel="noreferrer noopener">popularnej, acz słabej jakości witryny</a>. Zamiast tego wypada jednak dokładnie zapoznać się, do czego linkujemy, czy nie ma tam błędów merytorycznych, czy poruszone są wszystkie kwestie ważne poruszenia, itd. I tak jak w świecie nauki, w którym mamy tytuły godne zaufania (<a href="https://www.science.org/" rel="noreferrer noopener">Science</a>, <a href="https://www.nature.com/" rel="noreferrer noopener">Nature</a>), tak i w webdevie jedne źródła są bezpieczniejsze od innych. Najbezpieczniejsze są, rzecz jasna, specyfikacje i standardy. Nie ma pewniejszych źródeł od nich. Jeśli chcę opisać element <code>bdo</code>, to <a href="https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-bdo-element" rel="noreferrer noopener">specyfikacja HTML</a> jest Kanonicznym Źródłem Prawdy™. Ale standardy często są pisane w sposób całkowicie hermetyczny i niezrozumiały dla dowolnej osoby, która nie czyta sobie RFC do poduszki. Wtedy warto sięgnąć po drugie najlepsze źródło – <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/bdo" rel="noreferrer noopener">dokumentację MDN</a>. Jeśli coś można by nazwać <q>oficjalną dokumentacją platformy sieciowej</q>, to byłoby to właśnie MDN.</p>
<p>Dobrej jakości źródeł jest oczywiście więcej – jak choćby <a href="https://www.smashingmagazine.com/" rel="noreferrer noopener">Smashing Magazine</a>, <a href="https://alistapart.com/" rel="noreferrer noopener">A List Apart</a> czy blogi znanych osób ze światka webdevu. I często na tych stronach, oderwanych od “oficjalnego obiegu”, dzieją się rzeczy ciekawsze. To w końcu na łamach A List Apart powstał termin <a href="https://alistapart.com/article/responsive-web-design/" rel="noreferrer noopener">Responsive Web Design</a>! Często też wyłuskać można na jakiejś stronie jakąś perełkę wśród całej reszty <em>meh</em> artykułów (hej, to zupełnie jak na moim blogu!). Tylko no właśnie – <em>wyłuskać</em>…</p>
<p>Sprawne posługiwanie się źródłami wymaga mimo wszystko wprawy i pewnego doświadczenia. Ja w swoim życiu przerobiłem już <em>tysiące</em> artykułów o webdevie i jestem w stanie oddzielić te faktycznie ciekawe od tych, które takie nie są. I właśnie tę umiejętność selekcji uważam za kluczową w bardziej naukowym podejściu do webdevu. Żeby ją zdobyć, to nie ma innej rady – trzeba spędzić swoje na czytaniu. Na początku będzie się czytać wszystko, jak leci, by z czasem odrzucać te najgorsze z najgorszych, aż w końcu nadejdzie moment, w którym się Po Prostu Wie™, co jest warte poświęcenia czasu, a co nie.</p>
<p>Niemniej z selekcją źródeł jest jeszcze jeden mały haczyk: ryzyko wpadnięcia w bańkę. Każda osoba ma jakieś poglądy i przekonania. Choćby tak błahe, jak nielubienie Reacta czy skłonność do wybierania mniej popularnych rozwiązań. I takie przekonania będą – bardziej lub mniej świadomie – wpływać na to, które źródła się dobiera. Nie sądzę, by dało się od tego całkowicie uciec, ale im bardziej się jest tego świadomym, tym mniejszy ma to wpływ na proces selekcji. Bo czasami warto wręcz sięgać po źródła, z którymi się nie zgadzamy – choćby po to, by <a href="https://gwd.comandeer.pl/progressive-enhancement/#krytyka" rel="noreferrer noopener">wejść&nbsp;z nimi w polemikę</a>.</p>
<h3 id="empiryczność"><a class="header-anchor" href="https://blog.comandeer.pl/nullius-in-verba#empiryczność">Empiryczność</a></h3>
<p>Wreszcie ostatni element, który widać w większości moich artykułów – zarówno tutaj, jak i <a href="https://www.webkrytyk.pl/2021/10/31/wpadki-i-wypadki-14/" rel="noreferrer noopener">na WebKrytyku</a>. Empiryczność, czyli mówiąc inaczej: eksperymentowanie. Kiedy opisuję nowe API, fajnie byłoby, gdybym przygotował choćby krótkie demko, w którym bym zademonstrował jego podstawowe ficzery. Tym prostym sposobem można być jak Longinus Podbipięta i <s>ściąć trzy gł</s> odhaczyć trzy rzeczy:</p>
<ol>
<li>pokazujemy osobom czytającym,&nbsp;że opisywane przez nas rzeczy faktycznie istnieją i działają,</li>
<li>tworzymy dla siebie samych z przyszłości źródło do linkowania, jeśli kiedyś wspomnimy znowu o tym API,</li>
<li>zapamiętujemy całą rzecz lepiej, niż gdybyśmy naskrobali jedynie teoretyczny opis.</li>
</ol>
<p>Poza tym – ostatecznie piszę ten blog dla przyjemności. A gdzie byłby cały fun z tego, gdybym się nie bawił kodem?</p>
<h2 id="tylko-po-co"><a class="header-anchor" href="https://blog.comandeer.pl/nullius-in-verba#tylko-po-co">Tylko po co?</a></h2>
<p>Odpowiedziałem już na pytanie, <q>jak</q> traktować webdev bardziej naukowo. Pora zatem pochylić się nad drugim, równie ważnym – jeśli nawet nie ważniejszym – pytaniem: <q>po co</q>?</p>
<p>Bo uważam, że tego wymaga uczciwość&nbsp;intelektualna. Webdev nie jest jakąś bliżej niezdefiniowaną sztuką okultystyczną (mimo że czasami tak się jawi!). Wbrew pozorom zdecydowana większość platformy sieciowej jest oparta na konkretnych standardach i specyfikacjach. Bo gdyby nie była, strony WWW działałyby w jednych przeglądarkach i nie działały w innych. <a href="https://thehistoryoftheweb.com/browser-wars/" rel="noreferrer noopener">Te czasy już przerabialiśmy</a> i to właśnie dzięki nim dzisiaj mamy otwarte standardy sieciowe. Jasne, nie jest idealnie, ale inicjatywy takie jak <a href="https://wpt.fyi/" rel="noreferrer noopener">Web Platform Tests</a> czy <a href="https://web.dev/blog/interop-2025" rel="noreferrer noopener">Interop</a> dają nadzieję, ze będzie lepiej. A skoro Sieć oparta jest na fundamentach, które są skodyfikowane (spisane “na papierze”, z przybitą pieczątką) i możliwe do empirycznej weryfikacji (w każdej chwili mogę odpalić przeglądarkę i sprawdzić, jak ten HTML czy CSS działają), to nie widzę powodu, by moje artykuły się do tego nie odwoływały.</p>
<p>Uczciwość intelektualna wymaga też, by istniała pewna ciągłość między tym, co tworzymy, a tym, co zostało stworzone. Tak jak artykuł naukowy nie może istnieć bez źródeł, tak trudno stworzyć artykuł o hipertekście bez… hipertekstu. W webdevie nie ma <a href="https://en.wikipedia.org/wiki/Self-made_man" rel="noreferrer noopener"><i lang="en">self-made men</i></a>, wszyscy budujemy na fundamentach postawionych przez innych. Nawet jeśli nasze budowanie polega na niezgadzaniu się z już istniejącymi dobrymi praktykami i proponowaniu czegoś nowego. Bo ostatecznie nie byłoby tej propozycji, gdyby nie ta praktyka! Żeby się z czymś nie zgadzać, trzeba najpierw zauważyć istnienie tego czegoś. Inaczej <a href="https://www.webkrytyk.pl/2021/12/15/video-swiete-wojny-javascriptu-ile-h1-na-stronie-i-dlaczego-kuba-przespal-ostatnie-10-lat/" rel="noreferrer noopener">nasza krytyka będzie całkowicie jałowa</a>.</p>
<p>Wreszcie: webdev najzwyczajniej w świecie <em>zasługuje</em> na bardziej naukowe – czy też po prostu merytoryczne – traktowanie. Choćby dlatego, że Sieć stanowi coraz większą część&nbsp;naszego codziennego życia. To wszechobecna technologia, do której <a href="https://www.itu.int/en/mediacentre/Pages/PR-2025-11-17-Facts-and-Figures.aspx" rel="noreferrer noopener">dostęp ma <strong>ok. 6 miliardów ludzi</strong></a>. W innych dziedzinach nauki i technologii, które często dotykają mniejszej liczby osób (jak np. projekt nowego skafandra astronautycznego), zachowujemy niezwykłą precyzję i naukową rygorystyczność. Natomiast w dziedzinie, która w taki czy inny sposób zahacza o <em>jakieś ¾ światowej populacji</em>, mam wrażenie, że często wychodzimy z założenia, że <q>to tylko technologia</q>. A to przecież nieprawda. <a href="https://shkspr.mobi/blog/2021/01/the-unreasonable-effectiveness-of-simple-html/" rel="noreferrer noopener">Ludzie mają różne powody, by korzystać z Internetu</a>. Jeśli – jako osoby tworzące strony WWW – nie traktujemy Sieci wystarczająco poważnie, ostatecznie szkodzimy osobom, które z tych stron WWW następnie korzystają. I myślę, że przestawienie myślenia z <q>to tylko technologia</q> w kierunku <q>webdev to nauka</q> jest mało bolesnym sposobem na stworzenie lepszej Sieci.</p>
<p>I tym optymistycznym akcentem życzę Wszystkim wesołych świąt 🎄🎄🎄!</p>
]]></content>
		</entry>
	
		<entry>
			<title type="html">Dobry ziomek system</title>
			
				<author>
					<name>Comandeer</name>
				</author>
			
			<link href="https://blog.comandeer.pl/dobry-ziomek-system" rel="alternate" type="text/html"/>
			<published>2025-12-22T23:00:00.000Z</published>
			<updated>2025-12-22T23:00:00.000Z</updated>
			<id>https://blog.comandeer.pl/dobry-ziomek-system</id>
			
				<summary><![CDATA[Systemy operacyjne wcale nie są takie najgorsze, jeśli chodzi o dostępność.]]></summary>
			
			<content type="html"><![CDATA[<p>Dzisiaj chciałbym zwrócić uwagę na cichego bohatera dostępności: system operacyjny! Dostarcza on bowiem szeregu technologii asystujących oraz innych usprawnień dla osób z niepełnosprawnościami.</p>
<h2 id="technologia-asystująca"><a class="header-anchor" href="https://blog.comandeer.pl/dobry-ziomek-system#technologia-asystująca">Technologia asystująca</a></h2>
<p>Czym jednak jest technologia asystująca? Za <a href="https://www.who.int/news-room/fact-sheets/detail/assistive-technology" rel="noreferrer noopener">definicją proponowaną przez WHO</a>:</p>
<blockquote>
<p lang="en">Assistive products help maintain or improve an individual’s functioning related to cognition, communication, hearing, mobility, self-care and vision, thus enabling their health, well-being, inclusion and participation.</p>
<p>[Produkty asystujące pomagają w utrzymaniu lub poprawie funkcjonowania osoby w zakresie funkcji poznawczych, komunikacji, słuchu, mobilności, samoopieki oraz wzroku, pozwalając tej osobie być zdrową fizycznie i psychicznie, włączoną w życie społeczne oraz uczestniczącą w nim.]</p>
</blockquote>
<p>Ta definicja jest niezwykle szeroka i obejmuje tak naprawdę wszystkie sprzęty oraz oprogramowanie, które pomagają w codziennym funkcjonowaniu. Stąd można do niej zaliczyć np. wózek inwalidzki, czytniki ekranu, ale też choćby lupę. Swego czasu <a href="https://gwd.comandeer.pl/dostepnosc/technologia-asystujaca/" rel="noreferrer noopener">opisałem trochę przykładów takich technologii</a>.</p>
<h2 id="systemowa-technologia-asystująca"><a class="header-anchor" href="https://blog.comandeer.pl/dobry-ziomek-system#systemowa-technologia-asystująca">Systemowa technologia asystująca</a></h2>
<p>Systemy operacyjne dostarczają osobom z nich korzystających wbudowanych technologii asystujących. Lista takich technologii będzie się różnić w zależności od systemu. Weźmy jako przykład macOS-a. Chyba najbardziej znaną technologią asystującą dostępną wraz z tym systemem jest <a href="https://en.wikipedia.org/wiki/VoiceOver" rel="noreferrer noopener">czytnik ekranowy VoiceOver</a>. Nie jest bynajmniej jedyną. Ustawienia systemu posiadają mocno rozbudowaną sekcję poświęconą dostępności:</p>
<figure class="figure"><a class="figure__link" href="/assets/images/dobry-ziomek-system/macos-ustawienia-1360w.avif"><picture><source type="image/avif" srcset="/assets/images/dobry-ziomek-system/macos-ustawienia-440w.avif 440w, /assets/images/dobry-ziomek-system/macos-ustawienia-880w.avif 880w, /assets/images/dobry-ziomek-system/macos-ustawienia-1024w.avif 1024w, /assets/images/dobry-ziomek-system/macos-ustawienia-1360w.avif 1360w" sizes="90vw"><source type="image/webp" srcset="/assets/images/dobry-ziomek-system/macos-ustawienia-440w.webp 440w, /assets/images/dobry-ziomek-system/macos-ustawienia-880w.webp 880w, /assets/images/dobry-ziomek-system/macos-ustawienia-1024w.webp 1024w, /assets/images/dobry-ziomek-system/macos-ustawienia-1360w.webp 1360w" sizes="90vw"><source type="image/jpeg" srcset="/assets/images/dobry-ziomek-system/macos-ustawienia-440w.jpeg 440w, /assets/images/dobry-ziomek-system/macos-ustawienia-880w.jpeg 880w, /assets/images/dobry-ziomek-system/macos-ustawienia-1024w.jpeg 1024w, /assets/images/dobry-ziomek-system/macos-ustawienia-1360w.jpeg 1360w" sizes="90vw"><img src="/assets/images/dobry-ziomek-system/macos-ustawienia-1360w.jpeg" width="1360" height="1200" style="aspect-ratio: 1360 / 1200" alt="Aplikacja Ustawienia, zakładka &quot;Accessibility&quot;;&nbsp;w sekcji &quot;Vision&quot;&nbsp;znajdują się opcje &quot;VoiceOver&quot;, &quot;Zoom&quot;, &quot;Hover Text&quot;, &quot;Display&quot;, &quot;Motion&quot;, &quot;Read &amp; Speak&quot;, &quot;Audio Descriptions&quot;; w sekcji &quot;Hearing&quot;&nbsp;znajdują się opcje &quot;Hearing Devices&quot; oraz &quot;Audio&quot;; więcej opcji jest niewidocznych." loading="lazy" decoding="async"></picture></a><figcaption class="figure__caption"><p>Sekcja ustawień dostępności</p></figcaption></figure>
<p>Jak widać, macOS dzieli te ustawienia na poszczególne zmysły, które dane opcje mają wspierać. Stąd w kategorii wzroku mamy <a href="http://m.in" rel="noreferrer noopener">m.in</a>. czytnik ekranu (VoiceOver), ale też ustawienia wyświetlacza czy animacji ruchowych, w słuchu – ustawienia dźwięku itd. Każda z tych opcji w menu posiada konkretne ustawienia, np. odnośnie animacji ruchowych:</p>
<figure class="figure"><a class="figure__link" href="/assets/images/dobry-ziomek-system/macos-ruch-1360w.avif"><picture><source type="image/avif" srcset="/assets/images/dobry-ziomek-system/macos-ruch-440w.avif 440w, /assets/images/dobry-ziomek-system/macos-ruch-880w.avif 880w, /assets/images/dobry-ziomek-system/macos-ruch-1024w.avif 1024w, /assets/images/dobry-ziomek-system/macos-ruch-1360w.avif 1360w" sizes="90vw"><source type="image/webp" srcset="/assets/images/dobry-ziomek-system/macos-ruch-440w.webp 440w, /assets/images/dobry-ziomek-system/macos-ruch-880w.webp 880w, /assets/images/dobry-ziomek-system/macos-ruch-1024w.webp 1024w, /assets/images/dobry-ziomek-system/macos-ruch-1360w.webp 1360w" sizes="90vw"><source type="image/jpeg" srcset="/assets/images/dobry-ziomek-system/macos-ruch-440w.jpeg 440w, /assets/images/dobry-ziomek-system/macos-ruch-880w.jpeg 880w, /assets/images/dobry-ziomek-system/macos-ruch-1024w.jpeg 1024w, /assets/images/dobry-ziomek-system/macos-ruch-1360w.jpeg 1360w" sizes="90vw"><img src="/assets/images/dobry-ziomek-system/macos-ruch-1360w.jpeg" width="1360" height="1200" style="aspect-ratio: 1360 / 1200" alt="Aplikacja Ustawienia, zakładka &quot;Accessibility&quot;, podsekcja &quot;Motion&quot;; dostępne utawienia: &quot;Reduce motion&quot;, &quot;Dim flashing lights&quot;, &quot;Auto-play animated images&quot;, &quot;Prefer non-blinking cursor&quot;, &quot;Vehicle Motion Cues&quot;." loading="lazy" decoding="async"></picture></a><figcaption class="figure__caption"><p>Sekcja ustawień dostępności dotyczących animacji ruchowych</p></figcaption></figure>
<p>System od Apple pozwala na dostosowanie większości aspektów systemu, np. wyłączając autoodtwarzanie ruchomych obrazków (GIF-ów). I choć na początku ogrom opcji może przytłaczać, to sam fakt ich istnienia jest jak najbardziej pozytywny. W końcu jedne z najbardziej dostępnych rozwiązań to te, które można <a href="https://gwd.comandeer.pl/inkluzywnosc/preferencje-osoby-uzytkowniczej/" rel="noreferrer noopener">najbardziej dostosować pod siebie</a>!</p>
<p>Windows również posiada dość rozbudowane opcje dostępności. Podobnie jak macOS udostępnia czytnik ekranowy, <a href="https://www.microsoft.com/en-us/windows/tips/narrator" rel="noreferrer noopener">Narratora</a>. W przypadku jednak tego systemu nie zdobył on nigdy większej popularności. Od lat na tej platformie królują <a href="https://vispero.com/jaws-screen-reader-software/" rel="noreferrer noopener">JAWS</a> (płatny) oraz <a href="https://www.nvaccess.org/about-nvda/" rel="noreferrer noopener">NVDA</a> (darmowy). Oprócz czytnika Windows oferuje choćby <a href="https://support.microsoft.com/pl-pl/windows/u%C5%BCywanie-lupy-do-zapewnienia-lepszej-widoczno%C5%9Bci-element%C3%B3w-na-ekranie-414948ba-8b1c-d3bd-8615-0e5e32204198" rel="noreferrer noopener">lupę ekranową</a> (do powiększania fragmentów ekranu) czy <a href="https://blog.comandeer.pl/czy-div-jest-dostepny#dost%C4%99pno%C5%9B%C4%87-to-nie-tylko-czytniki-ekranowe">tryb wysokiego kontrastu</a>.</p>
<p>Systemy mobilne także dostarczają technologii asystujących. Zarówno Android, jak i iOS, mają wbudowane czytniki ekranowe – odpowiednio <a href="https://support.google.com/accessibility/android/answer/6007100?hl=en" rel="noreferrer noopener">TalkBack</a> i VoiceOver. Mają także choćby opcję ograniczania animacji ruchowych. Także sporo linuksowych dystrybucji ma ustawienia dostępności, np. LInux Mint pozwala włączyć tryb wysokiego kontrastu i ma wbudowany czytnik ekranu (<a href="https://orca.gnome.org/" rel="noreferrer noopener">Orcę</a>).</p>
<p>Innymi słowy: systemy operacyjne próbują dostarczyć niezbędnych narzędzi do tego, by mogło z nich korzystać jak najwięcej osób, w tym osoby z niepełnosprawnościami.</p>
<h2 id="system-a-przeglądarka"><a class="header-anchor" href="https://blog.comandeer.pl/dobry-ziomek-system#system-a-przeglądarka">System a przeglądarka</a></h2>
<p>Jak zatem taka systemowa technologia asystująca przekłada się na przeglądarkę? To zależy. Wraz z rozwojem technologii sieciowych, osoby tworzące strony WWW dostały możliwość dowiedzenia się nieco więcej o systemie operacyjnym, na którym uruchomiona jest przeglądarka. Najczęściej dzięki nowym media queries w CSS-ie. Wśród nich wymienić można:</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion" rel="noreferrer noopener"><code>prefers-reduced-motion</code></a> – informujące o ustawieniach dotyczących ograniczenia animacji ruchowych,</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/forced-colors" rel="noreferrer noopener"><code>forced-colors</code></a> – informujące o trybie wymuszonych kolorów, czyli ograniczeniu palety dostępnych kolorów, jak w przypadku Windowsowego trybu wysokiego kontrastu,</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-color-scheme" rel="noreferrer noopener"><code>prefers-color-scheme</code></a> – informujące o preferencjach osoby użytkowniczej co do doboru schematu kolorystycznego; inaczej mówiąc: czy woli jasny, czy ciemny motyw.</li>
</ul>
<p>Część z systemowych ułatwień dostępu może być jednak “zakamuflowana”. Dobrym przykładem są tu różnego rodzaju powiększenia. Działają one trochę jak zmniejszenie rozdzielczości: poszczególne elementy robią się większe, przez co są bardziej czytelne. Równocześnie jednak ogranicza to liczbę elementów widocznych w danej chwili na ekranie. Przeglądarka często interpretuje to jako mniejszy <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/CSSOM_view/Viewport_concepts" rel="noreferrer noopener">viewport</a>. Co też dobrze pokazuje, jak zawodne jest opieranie responsywności na założeniu <q>mały ekran = urządzenie mobilne</q>.</p>
<p>Jeszcze inne technologie asystujące są całkowicie przezroczyste dla przeglądarki, jak np. czytniki ekranu. Nie ma żadnego sposobu, aby dowiedzieć się, że osoba odwiedzająca stronę używa czytnika ekranu. I to <a href="https://axesslab.com/digital-apartheid/" rel="noreferrer noopener">akurat dobrze</a>. Zwłaszcza, że stworzenie strony z zachowaniem standardów sieciowych i dobrych praktyk dostępności jest w większości przypadków wystarczające, by strona ta działała poprawnie we wszystkich popularnych czytnikach ekranu. Innymi słowy: wystarczy <em>dobrze</em> wykonywać swoją pracę – jakkolwiek brutalnie by to nie brzmiało.</p>
<p>Podsumowując: przeglądarka i system to para zaufanych przyjaciół, która niektóre sekrety zostawia wyłącznie dla siebie. Ale to, czym się jednak z nami dzielą, powinno wystarczyć do stworzenia dostępnej, przyjaznej strony WWW.</p>
]]></content>
		</entry>
	
</feed>
