[{"data":1,"prerenderedAt":253},["ShallowReactive",2],{"lesson:t5-s05-forms-validation":3,"course:taropood":56},{"meta":4,"prev":10,"next":14,"sections":18},{"free_preview":5,"order":6,"slug":7,"source":8,"term":6,"title_fa":9},true,5,"t5-s05-forms-validation","book","فصل ۰۵ — اعتبارسنجی فرم",{"free_preview":5,"order":11,"slug":12,"source":8,"term":6,"title_fa":13},4,"t5-s04-forms-styling","فصل ۰۴ — استایل فرم",{"free_preview":5,"order":15,"slug":16,"source":8,"term":6,"title_fa":17},6,"t5-s06-transforms","فصل ۰۶ — transform",[19,23,26,31,34,37,40,43,46,49,53],{"kind":20,"heading":21,"html":22},"normal","در این فصل چه می‌سازی","\u003Ch2 id=\"در-این-فصل-چه-می‌سازی\">در این فصل چه می‌سازی\u003Ca class=\"head-anchor\" href=\"#%D8%AF%D8%B1-%D8%A7%DB%8C%D9%86-%D9%81%D8%B5%D9%84-%DA%86%D9%87-%D9%85%DB%8C%E2%80%8C%D8%B3%D8%A7%D8%B2%DB%8C\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>آخر این فصل یک فرمِ ثبت‌نامِ کوچک داری که \u003Cstrong>پیش از فرستادن\u003C\u002Fstrong>، خودش به کاربر می‌گوید چه چیزی درست است و چه چیزی نه: خانهٔ ایمیل وقتی درست پر شود سبز می‌شود و وقتی غلط باشد قرمز، و تیکِ «قوانین را می‌پذیرم» تا زده نشود فرم فرستاده نمی‌شود. نکتهٔ مهم این است که هیچ‌کدامِ این‌ها به JavaScript نیاز ندارد — خودِ مرورگر و چند خط CSS این کار را می‌کنند.\u003C\u002Fp>\n\u003Cp>\u003Cpicture>\u003Csource type=\"image\u002Fwebp\" srcset=\"\u002F_img\u002F01-image-valid-invalid-states.0c69d58537.160.webp 160w, \u002F_img\u002F01-image-valid-invalid-states.0c69d58537.320.webp 320w, \u002F_img\u002F01-image-valid-invalid-states.0c69d58537.640.webp 640w, \u002F_img\u002F01-image-valid-invalid-states.0c69d58537.1280.webp 1280w\" sizes=\"(max-width: 900px) 100vw, 800px\">\u003Cimg src=\"\u002F_img\u002F01-image-valid-invalid-states.0c69d58537.1280.jpg\" srcset=\"\u002F_img\u002F01-image-valid-invalid-states.0c69d58537.160.jpg 160w, \u002F_img\u002F01-image-valid-invalid-states.0c69d58537.320.jpg 320w, \u002F_img\u002F01-image-valid-invalid-states.0c69d58537.640.jpg 640w, \u002F_img\u002F01-image-valid-invalid-states.0c69d58537.1280.jpg 1280w\" sizes=\"(max-width: 900px) 100vw, 800px\" alt=\"یک فرمِ ساده در سه حالت کنارِ هم: خانهٔ ایمیلِ خالی با مرزِ خنثی، همان خانه با ورودیِ نادرست و مرزِ قرمز، و همان خانه با ورودیِ درست و مرزِ سبز\" width=\"1376\" height=\"768\" loading=\"lazy\" decoding=\"async\">\u003C\u002Fpicture>\u003C\u002Fp>\n\u003Cp>آخر این فصل می‌توانی:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>با attribute های \u003Ccode>required\u003C\u002Fcode>، \u003Ccode>type=&quot;email&quot;\u003C\u002Fcode>، \u003Ccode>min\u003C\u002Fcode>\u002F\u003Ccode>max\u003C\u002Fcode> و \u003Ccode>pattern\u003C\u002Fcode> بگذاری مرورگر خودش ورودی را بررسی کند\u003C\u002Fli>\n\u003Cli>با \u003Ccode>:required\u003C\u002Fcode>، \u003Ccode>:valid\u003C\u002Fcode> و \u003Ccode>:invalid\u003C\u002Fcode> ظاهرِ خانه‌ها را به وضعیتشان گره بزنی\u003C\u002Fli>\n\u003Cli>توضیح بدهی چرا یک خانهٔ خالیِ \u003Ccode>required\u003C\u002Fcode> از همان لحظهٔ اول \u003Ccode>:invalid\u003C\u002Fcode> است\u003C\u002Fli>\n\u003Cli>با \u003Ccode>:checked\u003C\u002Fcode> ظاهر را به تیک‌خوردنِ یک checkbox گره بزنی\u003C\u002Fli>\n\u003C\u002Ful>\n",{"kind":20,"heading":24,"html":25},"قبل از شروع","\u003Ch2 id=\"قبل-از-شروع\">قبل از شروع\u003Ca class=\"head-anchor\" href=\"#%D9%82%D8%A8%D9%84-%D8%A7%D8%B2-%D8%B4%D8%B1%D9%88%D8%B9\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>از فصل ۴ (همین ترم):\u003C\u002Fstrong> استایلِ \u003Ccode>&lt;input&gt;\u003C\u002Fcode> و \u003Ccode>&lt;button&gt;\u003C\u002Fcode>، selectorِ صفتی مثل \u003Ccode>[type=&quot;email&quot;]\u003C\u002Fcode>، و \u003Ccode>accent-color\u003C\u002Fcode> — فرم را از آنجا داریم و حالا اعتبارش را نشان می‌دهیم.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>از فصل ۲ (همین ترم):\u003C\u002Fstrong> \u003Ccode>:not()\u003C\u002Fcode> و combinatorِ \u003Ccode>+\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>مثل همیشه فقط یک مرورگر لازم داری، یا فقط همین آزمایشگاه.\u003C\u002Fp>\n",{"kind":27,"heading":28,"html":29,"embed":30},"lab","","— یک فرمِ ساده می‌بینی بدون هیچ بازخوردی. کارِ این فصل این است که خانه‌به‌خانه بازخوردِ اعتبارسنجی را رویش سوار کنی و هر بار نتیجه را با چشم ببینی","\u002Flab\u002Fembed\u002Ftaropood\u002Fterm-5-interaction\u002Fsession-05-forms-validation",{"kind":20,"heading":32,"html":33},"۱. مرورگر پیش از تو بررسی می‌کند","\u003Ch2 id=\"۱-مرورگر-پیش-از-تو-بررسی-می‌کند\">۱. مرورگر پیش از تو بررسی می‌کند\u003Ca class=\"head-anchor\" href=\"#%DB%B1-%D9%85%D8%B1%D9%88%D8%B1%DA%AF%D8%B1-%D9%BE%DB%8C%D8%B4-%D8%A7%D8%B2-%D8%AA%D9%88-%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D9%85%DB%8C%E2%80%8C%DA%A9%D9%86%D8%AF\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>قبل از هر CSS ای، یک چیزِ مهم را بدان: مرورگر \u003Cstrong>از قبل\u003C\u002Fstrong> یک اعتبارسنجیِ داخلی دارد. کافی است در HTML به آن بگویی هر خانه چه انتظاری دارد. این را با attribute می‌گویی:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>required\u003C\u002Fcode> — این خانه نباید خالی بماند.\u003C\u002Fli>\n\u003Cli>\u003Ccode>type=&quot;email&quot;\u003C\u002Fcode> — این خانه باید یک ایمیلِ درست باشد (یعنی یک \u003Ccode>@\u003C\u002Fcode> داشته باشد).\u003C\u002Fli>\n\u003Cli>\u003Ccode>min\u003C\u002Fcode> و \u003Ccode>max\u003C\u002Fcode> — کمینه و بیشینهٔ یک عدد (\u003Ccode>type=&quot;number&quot;\u003C\u002Fcode>).\u003C\u002Fli>\n\u003Cli>\u003Ccode>pattern\u003C\u002Fcode> — یک الگو که ورودی باید با آن جور دربیاید.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>فرمِ ما دو خانه دارد که هر دو \u003Ccode>required\u003C\u002Fcode> اند: یک ایمیل و یک checkbox. این HTML را در آزمایشگاه بنویس:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>&lt;form&gt;\n  &lt;label for=&quot;email&quot;&gt;ایمیل&lt;\u002Flabel&gt;\n  &lt;input type=&quot;email&quot; id=&quot;email&quot; name=&quot;email&quot; placeholder=&quot;you@example.com&quot; required&gt;\n\n  &lt;label class=&quot;terms&quot;&gt;\n    &lt;input type=&quot;checkbox&quot; name=&quot;agree&quot; required&gt;\n    &lt;span&gt;قوانین را می‌پذیرم&lt;\u002Fspan&gt;\n  &lt;\u002Flabel&gt;\n\n  &lt;button type=&quot;submit&quot;&gt;ثبت‌نام&lt;\u002Fbutton&gt;\n&lt;\u002Fform&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>حالا بدونِ اینکه چیزی پر کنی، دکمهٔ «ثبت‌نام» را بزن.\u003C\u002Fp>\n\u003Cp>✅ \u003Cstrong>چک کن:\u003C\u002Fstrong> فرم فرستاده نمی‌شود؛ مرورگر یک حبابِ کوچک بالای خانهٔ ایمیل نشان می‌دهد که می‌گوید این خانه لازم است. حالا یک متنِ بی‌ربط مثل \u003Ccode>abc\u003C\u002Fcode> در ایمیل بنویس و باز دکمه را بزن — این‌بار می‌گوید ایمیل معتبر نیست. همهٔ این‌ها را خودِ مرورگر انجام داد، بی‌یک خط CSS یا JavaScript.\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>💡 \u003Cstrong>نکته:\u003C\u002Fstrong> برای عددها همین کار را با \u003Ccode>min\u003C\u002Fcode> و \u003Ccode>max\u003C\u002Fcode> می‌کنی. مثلاً \u003Ccode>&lt;input type=&quot;number&quot; min=&quot;1&quot; max=&quot;5&quot;&gt;\u003C\u002Fcode> نمی‌گذارد کاربر عددی بیرونِ بازهٔ ۱ تا ۵ بفرستد. \u003Ccode>pattern\u003C\u002Fcode> هم یک الگوی دقیق‌تر می‌دهد. کارِ همهٔ این‌ها یکی است: قانونِ خانه را در HTML اعلام می‌کنی، بررسی‌اش با مرورگر است.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>\u003Cstrong>قبل از ادامه، جواب بده:\u003C\u002Fstrong> اگر \u003Ccode>required\u003C\u002Fcode> را از خانهٔ ایمیل برداری، زدنِ دکمه روی خانهٔ خالی باز هم جلوی فرستادن را می‌گیرد؟\u003C\u002Fp>\n\u003Chr>\n\u003Cp>\u003Cstrong>جواب:\u003C\u002Fstrong> نه. بدونِ \u003Ccode>required\u003C\u002Fcode> مرورگر خانهٔ خالی را مشکل نمی‌بیند، پس فرم فرستاده می‌شود. قانون را تو با attribute می‌گذاری؛ اگر نگذاری، بررسی‌ای هم نیست.\u003C\u002Fp>\n",{"kind":20,"heading":35,"html":36},"۲. :required: خانه‌های لازم را نشان بده","\u003Ch2 id=\"۲-required-خانه‌های-لازم-را-نشان-بده\">۲. \u003Ccode>:required\u003C\u002Fcode>: خانه‌های لازم را نشان بده\u003Ca class=\"head-anchor\" href=\"#%DB%B2-required-%D8%AE%D8%A7%D9%86%D9%87%E2%80%8C%D9%87%D8%A7%DB%8C-%D9%84%D8%A7%D8%B2%D9%85-%D8%B1%D8%A7-%D9%86%D8%B4%D8%A7%D9%86-%D8%A8%D8%AF%D9%87\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>حالا که مرورگر می‌داند کدام خانه لازم است، CSS هم می‌تواند همان را بداند. یک pseudo-class تازه داریم: \u003Ccode>:required\u003C\u002Fcode> به هر خانه‌ای می‌خورد که attributeِ \u003Ccode>required\u003C\u002Fcode> دارد. بیا خانه‌های لازم را با یک پس‌زمینهٔ گرم نشان بدهیم تا کاربر ببیند کدام‌ها را حتماً باید پر کند. اول استایلِ پایهٔ خانهٔ ایمیل، بعد قاعدهٔ \u003Ccode>:required\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>input[type=&quot;email&quot;] {\n  padding: 8px;\n  border: 2px solid #9a8c78;\n  border-radius: 6px;\n}\n\ninput:required {\n  background-color: #fbeecb;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>✅ \u003Cstrong>چک کن:\u003C\u002Fstrong> خانهٔ ایمیل یک پس‌زمینهٔ کرمِ ملایم می‌گیرد — نشانه‌ای که می‌گوید «این خانه لازم است». هنوز هیچ رنگِ سبز یا قرمزی نیست؛ فقط داریم می‌گوییم کدام خانه اجباری است.\u003C\u002Fp>\n",{"kind":20,"heading":38,"html":39},"۳. :valid و :invalid — و دامِ قرمزِ لحظهٔ اول","\u003Ch2 id=\"۳-valid-و-invalid-—-و-دامِ-قرمزِ-لحظهٔ-اول\">۳. \u003Ccode>:valid\u003C\u002Fcode> و \u003Ccode>:invalid\u003C\u002Fcode> — و دامِ قرمزِ لحظهٔ اول\u003Ca class=\"head-anchor\" href=\"#%DB%B3-valid-%D9%88-invalid-%E2%80%94-%D9%88-%D8%AF%D8%A7%D9%85%D9%90-%D9%82%D8%B1%D9%85%D8%B2%D9%90-%D9%84%D8%AD%D8%B8%D9%87%D9%94-%D8%A7%D9%88%D9%84\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>دو pseudo-classِ اصلیِ این فصل این‌هایند: \u003Ccode>:valid\u003C\u002Fcode> به خانه‌ای می‌خورد که ورودی‌اش قانون را رعایت کرده، و \u003Ccode>:invalid\u003C\u002Fcode> به خانه‌ای که رعایت نکرده. با این دو می‌توانی مرزِ خانه را سبز یا قرمز کنی. طبیعی است که اول این را بنویسی:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>input[type=&quot;email&quot;]:valid {\n  border-color: #2e7d32;\n}\n\ninput[type=&quot;email&quot;]:invalid {\n  border-color: #c62828;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>نگاه کن به صفحه. یک چیزِ عجیب می‌بینی: خانهٔ ایمیل \u003Cstrong>همین حالا\u003C\u002Fstrong>، پیش از اینکه حتی یک حرف تایپ کنی، مرزِ قرمز دارد. انگار فرم از کاربر عصبانی است قبل از اینکه کاری کرده باشد. این بدترین نوعِ بازخورد است.\u003C\u002Fp>\n\u003Cp>چرا این‌طور شد؟ چون خانهٔ ایمیل هم \u003Ccode>required\u003C\u002Fcode> است و هم خالی. یک خانهٔ \u003Ccode>required\u003C\u002Fcode>ِ خالی، قانونش را رعایت \u003Cstrong>نکرده\u003C\u002Fstrong> — پس از همان اولین لحظه \u003Ccode>:invalid\u003C\u002Fcode> است، بی‌آنکه کاربر خطایی کرده باشد. این دقیقاً همان تلهٔ معروفِ اعتبارسنجی است.\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>🔧 \u003Cstrong>اگر کار نکرد:\u003C\u002Fstrong> خانه از لحظهٔ باز شدنِ صفحه قرمز است؟ مشکل این است که \u003Ccode>:invalid\u003C\u002Fcode> به خانهٔ خالیِ لازم هم می‌خورد. راهِ درست این است که رنگ را فقط وقتی نشان بدهی که کاربر \u003Cstrong>چیزی تایپ کرده باشد\u003C\u002Fstrong>. برای این یک pseudo-classِ کمکی هست: \u003Ccode>:placeholder-shown\u003C\u002Fcode> به خانه‌ای می‌خورد که خالی است و placeholderش دیده می‌شود. پس \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> یعنی «فقط وقتی چیزی نوشته شده». این را به هر دو قاعده اضافه کن:\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>input[type=&quot;email&quot;]:not(:placeholder-shown):valid {\n  border-color: #2e7d32;\n}\n\ninput[type=&quot;email&quot;]:not(:placeholder-shown):invalid {\n  border-color: #c62828;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>✅ \u003Cstrong>چک کن:\u003C\u002Fstrong> حالا خانهٔ خالی مرزِ خنثی دارد، نه قرمز. یک \u003Ccode>abc\u003C\u002Fcode> بنویس — قرمز می‌شود. آن را پاک کن و یک ایمیلِ درست مثل \u003Ccode>a@b.co\u003C\u002Fcode> بنویس — سبز می‌شود. رنگ دیگر تنها وقتی می‌آید که کاربر واقعاً چیزی گفته باشد. (این خانه placeholder دارد؛ برای همین \u003Ccode>:placeholder-shown\u003C\u002Fcode> روی آن معنا پیدا می‌کند.)\u003C\u002Fp>\n\u003Cp>\u003Cstrong>قبل از ادامه، جواب بده:\u003C\u002Fstrong> چرا یک خانهٔ \u003Ccode>required\u003C\u002Fcode>ِ خالی از همان اول \u003Ccode>:invalid\u003C\u002Fcode> است، ولی یک خانهٔ \u003Cstrong>بدونِ\u003C\u002Fstrong> \u003Ccode>required\u003C\u002Fcode>ِ خالی این‌طور نیست؟\u003C\u002Fp>\n\u003Chr>\n\u003Cp>\u003Cstrong>جواب:\u003C\u002Fstrong> چون \u003Ccode>:invalid\u003C\u002Fcode> یعنی «قانونِ این خانه رعایت نشده». قانونِ خانهٔ \u003Ccode>required\u003C\u002Fcode> این است که «خالی نباش»، و خانهٔ خالی این قانون را می‌شکند — پس بی‌درنگ \u003Ccode>:invalid\u003C\u002Fcode> است. خانه‌ای که \u003Ccode>required\u003C\u002Fcode> نیست هیچ قانونی ندارد که بشکند، پس خالی هم که باشد \u003Ccode>:valid\u003C\u002Fcode> می‌ماند.\u003C\u002Fp>\n",{"kind":20,"heading":41,"html":42},"۴. :checked: ظاهر را به تیک گره بزن","\u003Ch2 id=\"۴-checked-ظاهر-را-به-تیک-گره-بزن\">۴. \u003Ccode>:checked\u003C\u002Fcode>: ظاهر را به تیک گره بزن\u003Ca class=\"head-anchor\" href=\"#%DB%B4-checked-%D8%B8%D8%A7%D9%87%D8%B1-%D8%B1%D8%A7-%D8%A8%D9%87-%D8%AA%DB%8C%DA%A9-%DA%AF%D8%B1%D9%87-%D8%A8%D8%B2%D9%86\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>آخرین pseudo-classِ این فصل \u003Ccode>:checked\u003C\u002Fcode> است: به یک checkbox یا radio می‌خورد که تیک خورده باشد. با آن می‌توانی وقتی کاربر تیک زد، چیزی روی صفحه عوض شود. بیا متنِ «قوانین را می‌پذیرم» را وقتی تیک خورد سبز و پررنگ کنیم. چون متن در یک \u003Ccode>&lt;span&gt;\u003C\u002Fcode>ِ \u003Cstrong>بعد از\u003C\u002Fstrong> checkbox است، از combinatorِ \u003Ccode>+\u003C\u002Fcode> (از فصل ۲) استفاده می‌کنیم:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>.terms input:checked + span {\n  color: #2e7d32;\n  font-weight: bold;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>✅ \u003Cstrong>چک کن:\u003C\u002Fstrong> روی checkbox تیک بزن — متنِ کنارش سبز و پررنگ می‌شود. تیک را بردار، به حالتِ عادی برمی‌گردد. \u003Ccode>input:checked + span\u003C\u002Fcode> یعنی «آن \u003Ccode>&lt;span&gt;\u003C\u002Fcode> ای که بلافاصله بعد از یک checkboxِ تیک‌خورده آمده».\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>⚠️ \u003Cstrong>مواظب باش:\u003C\u002Fstrong> \u003Ccode>:checked\u003C\u002Fcode> فقط به checkbox و radio می‌خورد، نه به خانه‌های متنی. برای خانهٔ متنی از \u003Ccode>:valid\u003C\u002Fcode>\u002F\u003Ccode>:invalid\u003C\u002Fcode> استفاده کن، و برای تیک از \u003Ccode>:checked\u003C\u002Fcode>. این‌ها را با هم قاطی نکن.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n",{"kind":20,"heading":44,"html":45},"۵. کد کامل","\u003Ch2 id=\"۵-کد-کامل\">۵. کد کامل\u003Ca class=\"head-anchor\" href=\"#%DB%B5-%DA%A9%D8%AF-%DA%A9%D8%A7%D9%85%D9%84\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>این هم دو فایلِ کاملِ فرم. اول \u003Ccode>index.html\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>&lt;!-- index.html --&gt;\n&lt;!DOCTYPE html&gt;\n&lt;html lang=&quot;fa&quot; dir=&quot;rtl&quot;&gt;\n  &lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n    &lt;title&gt;اعتبارسنجی فرم&lt;\u002Ftitle&gt;\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot;&gt;\n  &lt;\u002Fhead&gt;\n  &lt;body&gt;\n    &lt;form&gt;\n      &lt;label for=&quot;email&quot;&gt;ایمیل&lt;\u002Flabel&gt;\n      &lt;input type=&quot;email&quot; id=&quot;email&quot; name=&quot;email&quot; placeholder=&quot;you@example.com&quot; required&gt;\n\n      &lt;label class=&quot;terms&quot;&gt;\n        &lt;input type=&quot;checkbox&quot; name=&quot;agree&quot; required&gt;\n        &lt;span&gt;قوانین را می‌پذیرم&lt;\u002Fspan&gt;\n      &lt;\u002Flabel&gt;\n\n      &lt;button type=&quot;submit&quot;&gt;ثبت‌نام&lt;\u002Fbutton&gt;\n    &lt;\u002Fform&gt;\n  &lt;\u002Fbody&gt;\n&lt;\u002Fhtml&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>و \u003Ccode>styles.css\u003C\u002Fcode> — دقت کن که قاعده‌های \u003Ccode>:valid\u003C\u002Fcode>\u002F\u003Ccode>:invalid\u003C\u002Fcode> هر دو \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> دارند، همان راهِ درستی که تلهٔ قرمزِ لحظهٔ اول را می‌بندد:\u003C\u002Fp>\n\u003Cpre class=\"code-block\" dir=\"ltr\">\u003Ccode>\u002F* styles.css *\u002F\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  background-color: #f6edda;\n  font-family: system-ui, sans-serif;\n  padding: 24px;\n}\n\nform {\n  max-width: 320px;\n  display: grid;\n  gap: 12px;\n}\n\nlabel {\n  font-weight: bold;\n}\n\ninput[type=&quot;email&quot;] {\n  padding: 8px;\n  border: 2px solid #9a8c78;\n  border-radius: 6px;\n}\n\n\u002F* har field-e required yek pas-zamine-ye garm migirad *\u002F\ninput:required {\n  background-color: #fbeecb;\n}\n\n\u002F* rang-e marz faghat ba'd az inke karbar chizi tayp kard *\u002F\ninput[type=&quot;email&quot;]:not(:placeholder-shown):valid {\n  border-color: #2e7d32;\n}\n\ninput[type=&quot;email&quot;]:not(:placeholder-shown):invalid {\n  border-color: #c62828;\n}\n\n.terms {\n  font-weight: normal;\n}\n\n\u002F* matn-e label vaqti checkbox tik khord sabz mishavad *\u002F\n.terms input:checked + span {\n  color: #2e7d32;\n  font-weight: bold;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cpicture>\u003Csource type=\"image\u002Fwebp\" srcset=\"\u002F_img\u002F02-image-required-checked-map.feb41257ac.160.webp 160w, \u002F_img\u002F02-image-required-checked-map.feb41257ac.320.webp 320w, \u002F_img\u002F02-image-required-checked-map.feb41257ac.640.webp 640w, \u002F_img\u002F02-image-required-checked-map.feb41257ac.1200.webp 1200w\" sizes=\"(max-width: 900px) 100vw, 800px\">\u003Cimg src=\"\u002F_img\u002F02-image-required-checked-map.feb41257ac.1200.jpg\" srcset=\"\u002F_img\u002F02-image-required-checked-map.feb41257ac.160.jpg 160w, \u002F_img\u002F02-image-required-checked-map.feb41257ac.320.jpg 320w, \u002F_img\u002F02-image-required-checked-map.feb41257ac.640.jpg 640w, \u002F_img\u002F02-image-required-checked-map.feb41257ac.1200.jpg 1200w\" sizes=\"(max-width: 900px) 100vw, 800px\" alt=\"همان فرم با راهنمای رنگی: خانهٔ خالیِ لازم با پس‌زمینهٔ گرم و مرزِ خنثی، خانهٔ پرشدهٔ درست با مرزِ سبز، و متنِ کنارِ تیکِ خوردهٔ سبز\" width=\"1200\" height=\"896\" loading=\"lazy\" decoding=\"async\">\u003C\u002Fpicture>\u003C\u002Fp>\n\u003Cp>✅ \u003Cstrong>چک کن:\u003C\u002Fstrong> فرم را کامل کن — یک ایمیلِ درست بنویس و تیک را بزن. هر دو خانه بازخوردِ سبز می‌دهند و حالا دکمه فرم را می‌فرستد. یک بار هم خالی رهایش کن و دکمه را بزن تا حبابِ مرورگر را دوباره ببینی.\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>🤖 \u003Cstrong>با AI:\u003C\u002Fstrong> از دستیار AI ات بپرس «چرا خانهٔ \u003Ccode>required\u003C\u002Fcode> من از همان اول قرمز است؟». معمولاً جوابِ درستی می‌دهد، ولی گاهی راهی پیشنهاد می‌کند که با JavaScript یک class اضافه می‌کند — که برای این کار زیادی است. جوابش را با چیزی که در همین فصل دیدی بسنج: راهِ ساده‌ترِ بدونِ JavaScript همان \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> است. \u003Cstrong>AI هم اشتباه می‌کند\u003C\u002Fstrong> — گاهی راه‌حلی بزرگ‌تر از مسئله می‌دهد.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n",{"kind":20,"heading":47,"html":48},"واژه‌های تازهٔ این فصل","\u003Ch2 id=\"واژه‌های-تازهٔ-این-فصل\">واژه‌های تازهٔ این فصل\u003Ca class=\"head-anchor\" href=\"#%D9%88%D8%A7%DA%98%D9%87%E2%80%8C%D9%87%D8%A7%DB%8C-%D8%AA%D8%A7%D8%B2%D9%87%D9%94-%D8%A7%DB%8C%D9%86-%D9%81%D8%B5%D9%84\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>کلمه\u003C\u002Fth>\n\u003Cth>تلفظ به حروف فارسی\u003C\u002Fth>\n\u003Cth>یعنی چه\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>required\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>ریکوایِرد\u003C\u002Ftd>\n\u003Ctd>attribute ای که می‌گوید این خانه نباید خالی بماند\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>:required\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>ریکوایِرد\u003C\u002Ftd>\n\u003Ctd>pseudo-class ای که به خانه‌های لازم می‌خورد\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>:valid\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>ولید\u003C\u002Ftd>\n\u003Ctd>خانه‌ای که ورودی‌اش قانون را رعایت کرده\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>:invalid\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>این‌ولید\u003C\u002Ftd>\n\u003Ctd>خانه‌ای که ورودی‌اش قانون را رعایت نکرده\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>:checked\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>چِکد\u003C\u002Ftd>\n\u003Ctd>checkbox یا radio که تیک خورده باشد\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>:placeholder-shown\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>پلیس‌هولدر-شون\u003C\u002Ftd>\n\u003Ctd>خانه‌ای که خالی است و placeholderش دیده می‌شود\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n",{"kind":50,"heading":51,"html":52},"checkpoint","تمرین‌ها","\u003Ch2 id=\"تمرین‌ها\">تمرین‌ها\u003Ca class=\"head-anchor\" href=\"#%D8%AA%D9%85%D8%B1%DB%8C%D9%86%E2%80%8C%D9%87%D8%A7\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>قبل از تمرین، بدون نگاه‌کردن به بالا جواب بده: چرا \u003Ccode>:invalid\u003C\u002Fcode> را مستقیم و بدونِ \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> روی یک خانهٔ \u003Ccode>required\u003C\u002Fcode> نمی‌گذاریم؟\u003C\u002Fp>\n\u003Cp>\u003Cstrong>تمرین اجباری:\u003C\u002Fstrong> به فرم یک خانهٔ سوم اضافه کن: یک \u003Ccode>&lt;input type=&quot;number&quot; min=&quot;18&quot; max=&quot;99&quot; placeholder=&quot;مثلاً ۲۵&quot; required&gt;\u003C\u002Fcode> برای سن. همان قاعده‌های \u003Ccode>:valid\u003C\u002Fcode>\u002F\u003Ccode>:invalid\u003C\u002Fcode> را (با \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode>) برایش بنویس و ببین عددِ ۱۰ قرمز و عددِ ۲۰ سبز می‌شود. حواست به placeholder باشد: \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> فقط وقتی کار می‌کند که خانه placeholder داشته باشد — بی‌آن، همین خانهٔ خالیِ لازم از لحظهٔ اول قرمز می‌شود، دقیقاً همان تلهٔ این فصل.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>تمرین ستاره‌دار ⭐:\u003C\u002Fstrong> قاعدهٔ \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> را موقتاً از خانهٔ ایمیل بردار و صفحه را تازه کن. ببین خانه از لحظهٔ اول قرمز است. حالا در یک جمله بنویس چرا این بازخوردِ بد است، و دوباره \u003Ccode>:not(:placeholder-shown)\u003C\u002Fcode> را برگردان.\u003C\u002Fp>\n",{"kind":20,"heading":54,"html":55},"در فصل بعد","\u003Ch2 id=\"در-فصل-بعد\">در فصل بعد\u003Ca class=\"head-anchor\" href=\"#%D8%AF%D8%B1-%D9%81%D8%B5%D9%84-%D8%A8%D8%B9%D8%AF\" aria-label=\"پیوند به این بخش\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>الان می‌توانی فرم را زنده و باخبر کنی، همه بدونِ JavaScript. فصل بعد سراغِ \u003Cstrong>حرکت\u003C\u002Fstrong> می‌رویم: با \u003Ccode>transform\u003C\u002Fcode> یاد می‌گیری یک عنصر را بزرگ کنی، بچرخانی یا جابه‌جا کنی — مثلاً یک کارت که با \u003Ccode>:hover\u003C\u002Fcode> کمی بزرگ می‌شود. و یک نکتهٔ ظریف را می‌بینی: \u003Ccode>transform\u003C\u002Fcode> فقط ظاهر را جابه‌جا می‌کند، نه جای واقعیِ عنصر در چیدمان.\u003C\u002Fp>\n",{"course":57,"entitled":65,"lessons":66,"payments_enabled":65,"terms":252,"live":5},{"active_window":58,"effective_price_toman":59,"free":5,"lesson_count":60,"price_toman":61,"slug":62,"summary_fa":63,"title_fa":64},null,0,61,1500000,"taropood","از صفر تا ساختن سایت واقعی با HTML و CSS. متن‌محور، با آزمایشگاه زندهٔ داخل مرورگر و اصطلاح‌های اصیل.","تاروپود — خودآموز HTML و CSS",false,[67,71,75,79,82,85,88,92,96,100,104,107,110,113,116,119,122,125,128,131,134,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,192,195,198,201,204,205,206,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249],{"free_preview":5,"order":68,"slug":69,"source":8,"term":68,"title_fa":70},1,"t1-s01-first-page","فصل ۰۱ — اولین صفحهٔ وب تو",{"free_preview":5,"order":72,"slug":73,"source":8,"term":68,"title_fa":74},2,"t1-s02-text","فصل ۰۲ — متن: عنوان و پاراگراف",{"free_preview":5,"order":76,"slug":77,"source":8,"term":68,"title_fa":78},3,"t1-s03-links","فصل ۰۳ — پیوند: چیزی که وب را وب کرد",{"free_preview":5,"order":11,"slug":80,"source":8,"term":68,"title_fa":81},"t1-s04-images","فصل ۰۴ — تصویر",{"free_preview":5,"order":6,"slug":83,"source":8,"term":68,"title_fa":84},"t1-s05-lists","فصل ۰۵ — فهرست",{"free_preview":5,"order":15,"slug":86,"source":8,"term":68,"title_fa":87},"t1-s06-semantic","فصل ۰۶ — اسکلت معنادار صفحه",{"free_preview":5,"order":89,"slug":90,"source":8,"term":68,"title_fa":91},7,"t1-s07-tables","فصل ۰۷ — جدول، فقط برای داده",{"free_preview":5,"order":93,"slug":94,"source":8,"term":68,"title_fa":95},8,"t1-s08-forms","فصل ۰۸ — فرم: گرفتن ورودی",{"free_preview":5,"order":97,"slug":98,"source":8,"term":68,"title_fa":99},9,"t1-s09-accessibility","فصل ۰۹ — دسترس‌پذیری از همان HTML",{"free_preview":5,"order":101,"slug":102,"source":8,"term":68,"title_fa":103},10,"t1-s10-first-project","فصل ۱۰ — پروژه: صفحهٔ معرفی خودت",{"free_preview":5,"order":68,"slug":105,"source":8,"term":72,"title_fa":106},"t2-s01-first-css","فصل ۰۱ — اولین CSS",{"free_preview":5,"order":72,"slug":108,"source":8,"term":72,"title_fa":109},"t2-s02-selectors","فصل ۰۲ — selector ها",{"free_preview":5,"order":76,"slug":111,"source":8,"term":72,"title_fa":112},"t2-s03-cascade","فصل ۰۳ — cascade، specificity و inheritance",{"free_preview":5,"order":11,"slug":114,"source":8,"term":72,"title_fa":115},"t2-s04-box-model","فصل ۰۴ — جعبه‌ها: box model",{"free_preview":5,"order":6,"slug":117,"source":8,"term":72,"title_fa":118},"t2-s05-units-colors","فصل ۰۵ — واحد و رنگ",{"free_preview":5,"order":15,"slug":120,"source":8,"term":72,"title_fa":121},"t2-s06-typography","فصل ۰۶ — تایپوگرافی و فونت فارسی",{"free_preview":5,"order":89,"slug":123,"source":8,"term":72,"title_fa":124},"t2-s07-flow","فصل ۰۷ — جریان عادی صفحه",{"free_preview":5,"order":93,"slug":126,"source":8,"term":72,"title_fa":127},"t2-s08-decoration","فصل ۰۸ — پس‌زمینه، حاشیه، سایه",{"free_preview":5,"order":97,"slug":129,"source":8,"term":72,"title_fa":130},"t2-s09-custom-props","فصل ۰۹ — متغیرهای خودت در CSS",{"free_preview":5,"order":101,"slug":132,"source":8,"term":72,"title_fa":133},"t2-s10-devtools","فصل ۱۰ — DevTools: ابزار واقعی",{"free_preview":5,"order":135,"slug":136,"source":8,"term":72,"title_fa":137},11,"t2-s11-styled-project","فصل ۱۱ — صفحهٔ ترم ۱ را زنده کن",{"free_preview":5,"order":68,"slug":139,"source":8,"term":76,"title_fa":140},"t3-s01-layout-intro","فصل ۰۱ — چیدمان: از جریان عادی شروع کن",{"free_preview":5,"order":72,"slug":142,"source":8,"term":76,"title_fa":143},"t3-s02-flex-basics","فصل ۰۲ — flexbox: یک محور",{"free_preview":5,"order":76,"slug":145,"source":8,"term":76,"title_fa":146},"t3-s03-flex-align","فصل ۰۳ — چیدن و وسط‌چین کردن",{"free_preview":5,"order":11,"slug":148,"source":8,"term":76,"title_fa":149},"t3-s04-flex-grow","فصل ۰۴ — انعطاف واقعی",{"free_preview":5,"order":6,"slug":151,"source":8,"term":76,"title_fa":152},"t3-s05-grid-basics","فصل ۰۵ — grid: دو محور",{"free_preview":5,"order":15,"slug":154,"source":8,"term":76,"title_fa":155},"t3-s06-grid-placement","فصل ۰۶ — جای‌گذاری در grid",{"free_preview":5,"order":89,"slug":157,"source":8,"term":76,"title_fa":158},"t3-s07-grid-areas","فصل ۰۷ — layout کامل صفحه با grid",{"free_preview":5,"order":93,"slug":160,"source":8,"term":76,"title_fa":161},"t3-s08-position","فصل ۰۸ — position",{"free_preview":5,"order":97,"slug":163,"source":8,"term":76,"title_fa":164},"t3-s09-stacking","فصل ۰۹ — z-index و stacking context",{"free_preview":5,"order":101,"slug":166,"source":8,"term":76,"title_fa":167},"t3-s10-logical","فصل ۱۰ — logical properties",{"free_preview":5,"order":135,"slug":169,"source":8,"term":76,"title_fa":170},"t3-s11-layout-project","فصل ۱۱ — پروژه: layout یک سایت کامل",{"free_preview":5,"order":68,"slug":172,"source":8,"term":11,"title_fa":173},"t4-s01-responsive-intro","فصل ۰۱ — responsive یعنی چه",{"free_preview":5,"order":72,"slug":175,"source":8,"term":11,"title_fa":176},"t4-s02-media-queries","فصل ۰۲ — media query",{"free_preview":5,"order":76,"slug":178,"source":8,"term":11,"title_fa":179},"t4-s03-responsive-images","فصل ۰۳ — تصویر responsive",{"free_preview":5,"order":11,"slug":181,"source":8,"term":11,"title_fa":182},"t4-s04-fluid-type","فصل ۰۴ — تایپوگرافی سیال و ریاضی در CSS",{"free_preview":5,"order":6,"slug":184,"source":8,"term":11,"title_fa":185},"t4-s05-container-queries","فصل ۰۵ — container query",{"free_preview":5,"order":15,"slug":187,"source":8,"term":11,"title_fa":188},"t4-s06-responsive-nav","فصل ۰۶ — ناوبری responsive",{"free_preview":5,"order":89,"slug":190,"source":8,"term":11,"title_fa":191},"t4-s07-dark-mode","فصل ۰۷ — dark mode",{"free_preview":5,"order":93,"slug":193,"source":8,"term":11,"title_fa":194},"t4-s08-responsive-project","فصل ۰۸ — پروژه: سایت کاملاً responsive",{"free_preview":5,"order":68,"slug":196,"source":8,"term":6,"title_fa":197},"t5-s01-states","فصل ۰۱ — حالت‌ها: pseudo-class تعاملی",{"free_preview":5,"order":72,"slug":199,"source":8,"term":6,"title_fa":200},"t5-s02-structural-selectors","فصل ۰۲ — selector های ساختاری و combinator ها",{"free_preview":5,"order":76,"slug":202,"source":8,"term":6,"title_fa":203},"t5-s03-pseudo-elements","فصل ۰۳ — pseudo-element ها",{"free_preview":5,"order":11,"slug":12,"source":8,"term":6,"title_fa":13},{"free_preview":5,"order":6,"slug":7,"source":8,"term":6,"title_fa":9},{"free_preview":5,"order":15,"slug":16,"source":8,"term":6,"title_fa":17},{"free_preview":5,"order":89,"slug":208,"source":8,"term":6,"title_fa":209},"t5-s07-transitions","فصل ۰۷ — transition",{"free_preview":5,"order":93,"slug":211,"source":8,"term":6,"title_fa":212},"t5-s08-animation","فصل ۰۸ — animation و احترام به کاربر",{"free_preview":5,"order":97,"slug":214,"source":8,"term":6,"title_fa":215},"t5-s09-has-selector","فصل ۰۹ — :has() و تعامل بدون JavaScript",{"free_preview":5,"order":101,"slug":217,"source":8,"term":6,"title_fa":218},"t5-s10-interaction-project","فصل ۱۰ — پروژه: یک component تعاملی بدون JS",{"free_preview":5,"order":68,"slug":220,"source":8,"term":15,"title_fa":221},"t6-s01-organizing","فصل ۰۱ — CSS را سازماندهی کن",{"free_preview":5,"order":72,"slug":223,"source":8,"term":15,"title_fa":224},"t6-s02-layers-nesting","فصل ۰۲ — `@layer` و nesting",{"free_preview":5,"order":76,"slug":226,"source":8,"term":15,"title_fa":227},"t6-s03-components","فصل ۰۳ — مثل component فکر کن",{"free_preview":5,"order":11,"slug":229,"source":8,"term":15,"title_fa":230},"t6-s04-design-system","فصل ۰۴ — design system کوچک خودت",{"free_preview":5,"order":6,"slug":232,"source":8,"term":15,"title_fa":233},"t6-s05-svg-icons","فصل ۰۵ — SVG و آیکون",{"free_preview":5,"order":15,"slug":235,"source":8,"term":15,"title_fa":236},"t6-s06-accessibility-deep","فصل ۰۶ — دسترس‌پذیری عمیق",{"free_preview":5,"order":89,"slug":238,"source":8,"term":15,"title_fa":239},"t6-s07-performance","فصل ۰۷ — سرعت",{"free_preview":5,"order":93,"slug":241,"source":8,"term":15,"title_fa":242},"t6-s08-architecture","فصل ۰۸ — معماری CSS در مقیاس بزرگ",{"free_preview":5,"order":97,"slug":244,"source":8,"term":15,"title_fa":245},"t6-s09-debugging","فصل ۰۹ — اشکال‌زدایی مثل حرفه‌ای‌ها",{"free_preview":5,"order":101,"slug":247,"source":8,"term":15,"title_fa":248},"t6-s10-capstone-build","فصل ۱۰ — پروژهٔ نهایی: ساخت سایت چندصفحه‌ای",{"free_preview":5,"order":135,"slug":250,"source":8,"term":15,"title_fa":251},"t6-s11-capstone-ship","فصل ۱۱ — پروژهٔ نهایی: انتشار زنده",[],1784827105310]