درس ۴۴ از ۴۵ · صفحه‌های وب

صفحه‌های کامل: شش پروژه

عنصر و سبک و رویداد را یکی‌یکی آسان‌تر یاد می‌گیرید و کنار هم آسان‌تر به کار می‌برید. این درس شش صفحه‌ی کامل می‌سازد، هر کدام در حد چیزی که واقعاً منتشر می‌کنید. برای هر پروژه هدف، کدی که در پیش‌نمایش اجرا می‌شود، تصمیم‌های مهم و چند پیشنهاد برای ادامه را می‌بینید.

یک صفحه را چطور بسازیم

همه‌ی پروژه‌های زیر به یک ترتیب ساخته شده‌اند، و این ترتیب عادت خوبی است. اول محتوا: سرتیترها و متن را با عنصرهای ساده بنویسید، بدون هیچ سبکی، و ببینید صفحه معنا دارد. دوم ساختار: بخش‌ها را در عنصرهای ساختاری مثل سرصفحه، اصلی، بخش و پاورقی بگذارید (ساختار صفحه)، چون طرح کلی صفحه را می‌دهند. سوم ظاهر: رنگ، فاصله و چیدمان (سبک‌ها، چیدمان، صفحه‌های واکنش‌گرا). آخر رفتار: حالت، رویدادگیر و کمک‌تابع‌های دام (حالت، DOM و زمان‌سنج‌ها). صفحه‌ای که در هر قدم کار می‌کند تعمیرش آسان است. صفحه‌ای که پیش از داشتن محتوا سبک خورده باشد، نه.

دو عادت کد را کوتاه نگه می‌دارند. مقدارهایی که در چند جا می‌آیند، مثل رنگ نشان، بالای صفحه در یک ثابت می‌روند. تکه‌ای که بیش از یک بار می‌آید، مثل کارت قیمت یا یک آمار، بخش (component) می‌شود. همه‌ی پیش‌نمایش‌ها زنده‌اند: کلیک کنید، بنویسید و اندازه‌ی پنجره‌ی مرورگر را عوض کنید تا واکنش صفحه‌ها را ببینید.

پروژه‌ی ۱: صفحه‌ی فرود

هدف. یک صفحه که یک چیز می‌فروشد: سرصفحه با ناوبری، بخش اصلی با یک دعوت به اقدام، سه دلیل برای خرید، سه طرح و یک پاورقی. باید بدون نسخه‌ی جدای موبایل روی تلفن هم درست دیده شود.

web-project-landing.salam
پایا نشان := "کتری"
پایا تاکید := "#b45309"

بخش طرح(نام، بها، یادداشت):
    بخش:
        کلاس = "plan" پس زمینه = سفید کادر = "1px solid #e7e5e4" گردی کادر = 16 فاصله = 24 ترازمتن = وسط
        گذار = "transform 0.2s, box-shadow 0.2s"
        اشاره دگرگونی = "translateY(-4px)"
        اشاره سایه کادر = "0 12px 28px rgba(0,0,0,0.12)"
        سرتیتر: اندازه = 3 محتوا = نام فضا = "0 0 6px 0" پایان
        پاراگراف: محتوا = بها اندازه قلم = "2.2rem" وزن قلم = پررنگ رنگ = تاکید فضا = 0 پایان
        پاراگراف: محتوا = یادداشت رنگ = "#78716c" فضا = "4px 0 16px 0" پایان
        محتوا: پایان
        دکمه: محتوا = "انتخاب " + نام فاصله = "10px 22px" کادر = 0 گردی کادر = 999 پس زمینه = "#292524" رنگ = سفید نشانگر = اشاره‌گر خانواده قلم = inherit اشاره پس زمینه = تاکید پایان
    پایان
پایان

صفحه:
    عنوان = "باشگاه قهوه‌ی " + نشان
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 رنگ = "#292524" پس زمینه = "#fafaf9" ارتفاع خط = 1.8 پایان
    سرصفحه:
        نمایش = فلکس چینش = "space-between" ترازعمودی = وسط فاصله = "16px 6vw"
        قوی: محتوا = نشان اندازه قلم = "1.4rem" رنگ = تاکید پایان
        ناوبری: نمایش = فلکس شکاف = 22
            پیوند: نشانی = "#features" محتوا = "چرا ما" رنگ = "#44403c" تزیین متن = هیچ اشاره رنگ = تاکید پایان
            پیوند: نشانی = "#plans" محتوا = "طرح‌ها" رنگ = "#44403c" تزیین متن = هیچ اشاره رنگ = تاکید پایان
        پایان
    پایان
    اصلی:
        بخش:
            فاصله = "72px 6vw" ترازمتن = وسط پس زمینه = "linear-gradient(135deg, #fef3c7, #fed7aa)"
            سرتیتر: اندازه = 1 محتوا = "هر دوشنبه قهوه‌ی تازه" اندازه قلم = "clamp(2rem, 6vw, 3.4rem)" فضا = "0 0 12px 0" پایان
            پاراگراف: محتوا = "دانه‌هایی که همین هفته برشته شده‌اند، به اندازه‌ی دلخواه شما آسیاب می‌شوند و پیش از صبحانه دم در خانه‌اند." بیشینه عرض = "34rem" فضا = "0 auto 24px auto" اندازه قلم = "1.15rem" پایان
            دکمه: محتوا = "اولین بسته‌ام را می‌خواهم" فاصله = "14px 30px" کادر = 0 گردی کادر = 999 پس زمینه = تاکید رنگ = سفید اندازه قلم = "1.05rem" نشانگر = اشاره‌گر خانواده قلم = inherit اشاره پس زمینه = "#92400e" پایان
        پایان
        بخش:
            شناسه = "features" فاصله = "56px 6vw"
            سرتیتر: اندازه = 2 محتوا = "چرا می‌مانند" ترازمتن = وسط فضا = "0 0 28px 0" پایان
            جعبه: نمایش = شبکه ستون های شبکه = "repeat(auto-fit, minmax(200px, 1fr))" شکاف = 24
                جعبه: سرتیتر: اندازه = 3 محتوا = "برشته‌ی سفارش شما" پایان پاراگراف: محتوا = "هیچ بسته‌ای روی قفسه نمی‌ماند. هر بسته پس از سفارش شما برشته می‌شود." پایان پایان
                جعبه: سرتیتر: اندازه = 3 محتوا = "رد کردن یا توقف" پایان پاراگراف: محتوا = "سفر می‌روید؟ با دو کلیک متوقف کنید. بدون جریمه و بدون تماس." پایان پایان
                جعبه: سرتیتر: اندازه = 3 محتوا = "قیمت منصفانه" پایان پاراگراف: محتوا = "از مزرعه‌هایی می‌خریم که می‌شناسیم و می‌گوییم هر کدام چه دریافت کرده‌اند." پایان پایان
            پایان
        پایان
        بخش:
            شناسه = "plans" فاصله = "56px 6vw" پس زمینه = "#f5f5f4"
            سرتیتر: اندازه = 2 محتوا = "طرح خود را انتخاب کنید" ترازمتن = وسط فضا = "0 0 28px 0" پایان
            جعبه: نمایش = شبکه ستون های شبکه = "repeat(auto-fit, minmax(220px, 1fr))" شکاف = 24
                طرح: نام = "تکی" بها = "۲۹۰ هزار" یادداشت = "ماهی یک بسته" پاراگراف: محتوا = "۲۵۰ گرم، هر برشته‌ای" پایان پایان
                طرح: نام = "دونفره" بها = "۵۲۰ هزار" یادداشت = "ماهی دو بسته" پاراگراف: محتوا = "۲ بسته‌ی ۲۵۰ گرمی، مخلوط" پایان پایان
                طرح: نام = "دفتر" بها = "۱٫۴ میلیون" یادداشت = "ماهی شش بسته" پاراگراف: محتوا = "۶ بسته‌ی ۲۵۰ گرمی، همراه نکته‌های آسیاب" پایان پایان
            پایان
        پایان
    پایان
    پاورقی: فاصله = "28px 6vw" ترازمتن = وسط رنگ = "#78716c" محتوا = "باشگاه قهوه‌ی کتری. ساخته‌شده با دقت در یک آشپزخانه‌ی کوچک." پایان
پایان

شرح. صفحه چند نوار تمام‌عرض است که درون اصلی روی هم چیده شده‌اند، و هر نوار یک بخش است که پس‌زمینه و فاصله‌ی خودش را دارد. 6vw فاصله از چپ و راست متن را روی هر اندازه‌ی صفحه از لبه‌ها دور نگه می‌دارد، و سرتیتر با clamp(2rem, 6vw, 3.4rem) با پنجره بزرگ می‌شود اما هرگز زیادی کوچک یا بزرگ نمی‌شود.

ستون‌ها به رسانه‌ی پرسشی (media query) نیاز ندارند. repeat(auto-fit, minmax(220px, 1fr)) می‌گوید: هر چند ستون که جا می‌شود بساز، هر کدام دست‌کم ۲۲۰ پیکسل، و باقی را مساوی تقسیم کن. سه کارت روی لپ‌تاپ کنار هم‌اند و همین قاعده روی تلفن آن‌ها را زیر هم می‌چیند. کارت‌های قیمت یک بخش به نام طرح با سه پارامتر هستند. سطر محتوا: پایان درونش یک جای خالی است: هر چه بین طرح: و پایان آن بنویسید همان‌جا می‌نشیند، پس هر طرح می‌تواند جزئیات خودش را داشته باشد. ظاهرش هنگام اشاره، کمی بالا آمدن و یک سایه، یک بار با پیشوند اشاره و یک گذار نوشته شده که تغییر را نرم می‌کند. نشان و تاکید ثابت‌اند، پس عوض کردن رنگ کل صفحه یک ویرایش یک‌سطری است.

قدم بعد. طرح وسط را با کادر پررنگ‌تر و یک نشان کوچک متمایز کنید. یک قاعده‌ی رسانه بنویسید که روی صفحه‌های خیلی باریک سرصفحه را زیر هم بچیند. دعوت به اقدام را به پیوند صفحه‌ی عضویت تبدیل کنید و فرمی مثل پروژه‌ی ۳ بسازید.

پروژه‌ی ۲: نوشته‌ی وبلاگ با ستون کناری

هدف. یک صفحه‌ی راحت برای خواندن: سرصفحه، یک مقاله با تصویر و نقل قول، و یک ستون کناری که وقتی صفحه باریک است زیر مقاله می‌رود.

web-project-blog.salam
بخش برچسب‌ها(نام):
    پیوند: نشانی = "#" محتوا = نام نمایش = "inline-block" فاصله = "3px 12px" فضا = "0 0 6px 6px" گردی کادر = 999 پس زمینه = "#e0f2f1" رنگ = "#115e59" تزیین متن = هیچ اندازه قلم = "0.9rem" اشاره پس زمینه = "#99f6e4" پایان
پایان

صفحه:
    عنوان = "یادداشت‌های باغ: چرا مالچ مهم است"
    سراسری: گزینشگر = "nav a" تزیین متن = هیچ پایان
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 رنگ = "#1c1917" پس زمینه = "#fffdf8" ارتفاع خط = 2 پایان
    سرصفحه:
        فاصله = "18px 5vw" کادر پایین = "1px solid #e7e5e4" نمایش = فلکس چینش = "space-between" ترازعمودی = "baseline" پیچش فلکس = "wrap" شکاف = 8
        قوی: محتوا = "یادداشت‌های باغ" اندازه قلم = "1.5rem" رنگ = "#0f766e" پایان
        ناوبری: نمایش = فلکس شکاف = 18 اندازه قلم = "0.95rem"
            پیوند: نشانی = "#" محتوا = "خانه" رنگ = "#44403c" پایان
            پیوند: نشانی = "#" محتوا = "بایگانی" رنگ = "#44403c" پایان
            پیوند: نشانی = "#" محتوا = "درباره" رنگ = "#44403c" پایان
        پایان
    پایان
    جعبه:
        نمایش = شبکه ستون های شبکه = "minmax(0, 1fr) 17rem" شکاف = 40 فاصله = "36px 5vw" بیشینه عرض = "70rem" فضا = "0 auto"
        رسانه: شرط = "(max-width: 760px)" ستون های شبکه = "1fr" شکاف = 24 پایان
        اصلی:
            مقاله:
                سرصفحه:
                    سرتیتر: اندازه = 1 محتوا = "چرا مالچ مهم است" اندازه قلم = "2.2rem" ارتفاع خط = 1.4 فضا = "0 0 8px 0" پایان
                    پاراگراف: رنگ = "#78716c" فضا = "0 0 24px 0" اندازه قلم = "0.9rem"
                        محتوا = "نوشته‌ی سارا نیکو، "
                        زمان: زمان دقیق = "2026-10-26" محتوا = "۴ آبان ۱۴۰۵" پایان
                        تکه: محتوا = "، ۴ دقیقه مطالعه" پایان
                    پایان
                پایان
                شکل:
                    فضا = "0 0 24px 0"
                    جعبه: ارتفاع = 220 گردی کادر = 14 پس زمینه = "linear-gradient(160deg, #86efac, #166534)" پایان
                    زیرنویس شکل: محتوا = "لایه‌ای ضخیم از کاه، یک هفته پس از کاشت." رنگ = "#78716c" اندازه قلم = "0.85rem" فضا بالا = 8 پایان
                پایان
                پاراگراف: محتوا = "خاک لخت زود آب از دست می‌دهد. لایه‌ای از کاه یا برگ آفتاب را از آن دور نگه می‌دارد و بستر تا چند روز پس از باران نمناک می‌ماند." پایان
                سرتیتر: اندازه = 2 محتوا = "علف هرز کمتر" فضا = "28px 0 8px 0" پایان
                پاراگراف: محتوا = "دانه در تاریکی جوانه نمی‌زند. مالچ را پنج سانتی‌متر ضخیم بریزید تا بیشتر علف‌های هرز هرگز شروع نکنند." پایان
                نقل قول بلند: فضا = "24px 0" فاصله = "4px 20px" کادر خطی آغاز = "4px solid #14b8a6" رنگ = "#134e4a" سبک قلم = کج محتوا = "بهترین ابزار باغ من یک فرغون کاه کهنه است." پایان
                پاراگراف: محتوا = "آن را به اندازه‌ی یک وجب از ساقه‌ها دور نگه دارید تا نفس بکشند." پایان
            پایان
        پایان
        کناری:
            سرتیتر: اندازه = 2 محتوا = "درباره‌ی نویسنده" اندازه قلم = "1.1rem" فضا = "0 0 6px 0" پایان
            پاراگراف: محتوا = "سارا در بالکن کوچکش سبزی می‌کارد و از آنچه جواب می‌دهد می‌نویسد." اندازه قلم = "0.95rem" رنگ = "#57534e" پایان
            سرتیتر: اندازه = 2 محتوا = "موضوع‌ها" اندازه قلم = "1.1rem" فضا = "22px 0 8px 0" پایان
            جعبه: برچسب‌ها: نام = "خاک" پایان برچسب‌ها: نام = "آب" پایان برچسب‌ها: نام = "علف هرز" پایان برچسب‌ها: نام = "کود" پایان پایان
        پایان
    پایان
    پاورقی: فاصله = "24px 5vw" کادر بالا = "1px solid #e7e5e4" رنگ = "#78716c" اندازه قلم = "0.9rem" محتوا = "یادداشت‌های باغ. آهسته نوشته شده." پایان
پایان

شرح. خواندن اصل کار است، پس قاعده‌های متن اول می‌آیند: یک ارتفاع خط بلند و ستونی که از آنچه صفحه اجازه می‌دهد پهن‌تر نمی‌شود. چیدمان دوستونه یک شبکه با minmax(0, 1fr) 17rem است: ستون کناری ثابت ۱۷rem است و مقاله باقی را می‌گیرد. صفر در minmax مهم است، چون بدونش یک کلمه‌ی بلند یا تصویر پهن می‌تواند ستون را از صفحه پهن‌تر کند. جعبه بیشینه عرض دارد و فضا = "0 auto"، که روی نمایشگر بزرگ آن را وسط می‌گذارد.

بخش واکنش‌گرا فرزند رسانه: شبکه است. زیر ۷۶۰ پیکسل دو ستون را با یکی عوض می‌کند، و چون ستون کناری در متن برنامه دوم است، زیر مقاله می‌افتد. ترتیب در متن برنامه همان ترتیب روی تلفن است، پس بخش‌ها را به ترتیبی بنویسید که خواننده‌ی تلفن باید ببیندشان. سطر اطلاعات زمان را با زمان دقیق قابل‌خواندن برای ماشین دارد، تصویر در یک شکل با زیرنویس شکل است، و نقل قول یک نقل قول بلند است که نوارش کادر خطی آغاز است. آغاز و پایان کناره‌های منطقی‌اند: در صفحه‌ی راست‌به‌چپ نوار خودش به لبه‌ی راست می‌رود. برچسب‌ها بخش کوچکی برای قرص‌های موضوع است.

قدم بعد. فهرست مطالب را به شکل یک ناوبری با پیوند به سرتیترها بسازید (به سرتیترها شناسه بدهید). نسخه‌ی تاریک را با یک عنصر style و prefers-color-scheme اضافه کنید. چاپش را درست کنید: قاعده‌ای با رسانه = "print" که ستون کناری را پنهان کند.

پروژه‌ی ۳: فرم عضویت با بررسی زنده

هدف. فرمی که همان‌طور که تایپ می‌کنند می‌گوید چه اشکالی هست، نه بعد از فشردن دکمه: کادر سبز یا قرمز برای هر خانه، پیامی زیرش، نوار قدرت رمز، و دکمه‌ی عضویتی که تا همه چیز درست نشده خاموش می‌ماند.

web-project-signup.salam
واردسازی دام

ناپایا دیده := نادرست

تابع داوری(خانه: رشته، خوب: منطقی، پیام: رشته):
    عنصر := دام.با شناسه(خانه)
    دام.حذف کلاس(عنصر، "good")
    دام.حذف کلاس(عنصر، "bad")
    اگر دام.دریافت مقدار(عنصر).طول() > 0:
        اگر خوب:
            دام.افزودن کلاس(عنصر، "good")
        وگرنه:
            دام.افزودن کلاس(عنصر، "bad")
        پایان
    پایان
    اگر خوب:
        دام.تنظیم متن(دام.با شناسه(خانه + "-note")، "")
    وگرنه:
        دام.تنظیم متن(دام.با شناسه(خانه + "-note")، پیام)
    پایان
پایان

تابع بسنج:
    رمز := دام.دریافت مقدار(دام.با شناسه("pw"))
    ناپایا امتیاز := 0
    اگر رمز.طول() >= 8:
        امتیاز += 1
    پایان
    اگر رمز.lower() != رمز:
        امتیاز += 1
    پایان
    تکرار 10 در رقم:
        اگر رمز.دربردارد("" + رقم):
            امتیاز = امتیاز + 1
            بشکن
        پایان
    پایان
    ایمیل := دام.دریافت مقدار(دام.با شناسه("mail"))
    نامخوب := دام.دریافت مقدار(دام.با شناسه("name")).طول() >= 2
    ایمیلخوب := ایمیل.دربردارد("@") و ایمیل.دربردارد(".") و ایمیل.طول() >= 6
    رمزخوب := امتیاز == 3
    تکرارخوب := رمز.طول() > 0 و دام.دریافت مقدار(دام.با شناسه("again")) == رمز
    داوری("name"، نامخوب، "لطفاً نامتان را بنویسید.")
    داوری("mail"، ایمیلخوب، "این شبیه نشانی ایمیل نیست.")
    داوری("pw"، رمزخوب، "رمز باید ۸ نویسه، یک حرف بزرگ و یک رقم داشته باشد.")
    داوری("again"، تکرارخوب، "دو رمز یکی نیستند.")
    دام.تنظیم سبک(دام.با شناسه("meter")، "width"، "" + امتیاز * 33 + "%")
    دام.تنظیم خاصیت منطقی(دام.با شناسه("join")، "disabled"، وارونه (نامخوب و ایمیلخوب و رمزخوب و تکرارخوب))
پایان

تابع نمایش:
    دیده = وارونه دیده
    اگر دیده:
        دام.تنظیم ویژگی(دام.با شناسه("pw")، "type"، "text")
    وگرنه:
        دام.تنظیم ویژگی(دام.با شناسه("pw")، "type"، "password")
    پایان
پایان

تابع خوشامد(رویداد: صحیح۶۴):
    دام.جلوگیری پیش فرض(رویداد)
    دام.تنظیم متن(دام.با شناسه("done")، "خوش آمدید " + دام.دریافت مقدار(دام.با شناسه("name")) + ". صندوق ایمیلتان را ببینید.")
پایان

صفحه:
    عنوان = "ساختن حساب"
    ظاهر سفارشی: محتوا = "input { width: 100%; box-sizing: border-box; padding: 10px 12px; border: 2px solid #cbd5e1; border-radius: 8px; font-size: 1rem; font-family: inherit; outline: none } input:focus { border-color: #6366f1 } input.good { border-color: #22c55e } input.bad { border-color: #ef4444 } label { display: block; margin: 14px 0 4px; font-weight: 600 } button:disabled { opacity: 0.5; cursor: not-allowed } .note { color: #dc2626; font-size: 0.85rem; min-height: 1.2em; margin: 4px 0 0 }" پایان
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 پس زمینه = "#eef2ff" پایان
    فرم: شناسه = "signup" ارسال = خوشامد بیشینه عرض = "24rem" فضا = "28px auto" فاصله = 28 پس زمینه = سفید گردی کادر = 16 سایه کادر = "0 10px 30px rgba(79,70,229,0.15)"
        سرتیتر: اندازه = 2 محتوا = "ساختن حساب" فضا = "0 0 4px 0" پایان
        برچسب: برای = "name" محتوا = "نام" پایان
        ورودی: شناسه = "name" ورودی = بسنج تکمیل خودکار = "name" پایان
        پاراگراف: شناسه = "name-note" کلاس = "note" پایان
        برچسب: برای = "mail" محتوا = "ایمیل" پایان
        ورودی: شناسه = "mail" نوع = ایمیل ورودی = بسنج تکمیل خودکار = "email" جهت = "ltr" پایان
        پاراگراف: شناسه = "mail-note" کلاس = "note" پایان
        برچسب: برای = "pw" محتوا = "رمز" پایان
        ورودی: شناسه = "pw" نوع = "password" ورودی = بسنج تکمیل خودکار = "new-password" جهت = "ltr" پایان
        جعبه: ارتفاع = 6 پس زمینه = "#e2e8f0" گردی کادر = 3 فضا = "6px 0" جعبه: شناسه = "meter" ارتفاع = "100%" عرض = "0%" پس زمینه = "#6366f1" گردی کادر = 3 گذار = "width 0.2s" پایان پایان
        پاراگراف: شناسه = "pw-note" کلاس = "note" پایان
        دکمه: شناسه = "peek" نوع = "button" کلیک = نمایش محتوا = "نشان دادن یا پنهان کردن رمز" پس زمینه = هیچ کادر = 0 رنگ = "#4f46e5" نشانگر = اشاره‌گر فاصله = 0 خانواده قلم = inherit پایان
        برچسب: برای = "again" محتوا = "تکرار رمز" پایان
        ورودی: شناسه = "again" نوع = "password" ورودی = بسنج جهت = "ltr" پایان
        پاراگراف: شناسه = "again-note" کلاس = "note" پایان
        دکمه: شناسه = "join" نوع = ارسال غیرفعال = درست محتوا = "عضویت" عرض = "100%" فاصله = 12 فضا = "10px 0 0 0" کادر = 0 گردی کادر = 10 پس زمینه = "#4f46e5" رنگ = سفید اندازه قلم = "1rem" نشانگر = اشاره‌گر خانواده قلم = inherit پایان
        پاراگراف: شناسه = "done" رنگ = "#15803d" وزن قلم = 600 پایان
    پایان
پایان

شرح. برای هر خانه رویدادگیر جدا نیست. همه‌ی خانه‌ها یک ورودی = بسنج دارند و بسنج هر چهار خانه را می‌خواند و دوباره درباره‌ی همه تصمیم می‌گیرد. این همان الگوی درس حالت است: فرم هر بار از روی مقدارهایش دوباره کشیده می‌شود، پس هرگز نیمه‌تازه نمی‌ماند. داوری کشیدن یک خانه را انجام می‌دهد. هر دو کلاس را برمی‌دارد، good یا bad را فقط وقتی خانه خالی نیست می‌افزاید (کسی نمی‌خواهد روی فرمی که به آن دست نزده قرمز ببیند) و پیام را می‌نویسد یا پاک می‌کند. سه رنگ در CSS درون عنصر style و کنار input:focus هستند، چون وضعیت یک عنصرند و تصمیم اسکریپت نیستند.

امتیاز رمز سه چیز را می‌شمارد، طول، یک حرف بزرگ و یک رقم، و نوار امتیاز * 33 درصد را نشان می‌دهد. دکمه‌ی نمایش type خانه را با دام.تنظیم ویژگی بین password و text عوض می‌کند. خانه‌ی ایمیل نوع = ایمیل و مقدار تکمیل خودکار دارد، پس تلفن‌ها صفحه‌کلید درست را نشان می‌دهند و مدیر رمز می‌داند چه پر کند. رویدادگیر ارسال فرم دام.جلوگیری پیش فرض(رویداد) را صدا می‌زند و به‌جای فرستادن چیزی یک خوشامد نشان می‌دهد، چون پیش‌نمایش سرور ندارد. خانه‌های ایمیل و رمز جهت = "ltr" دارند، چون نشانی ایمیل و رمز چپ‌به‌راست نوشته می‌شوند.

نام تابع رویدادگیر را با شناسه هیچ دکمه یا خانه‌ی فرم یکی نکنید. دکمه‌ای با شناسه = "join" و تابعی به نام join با هم کنار نمی‌آیند: درون فرم مرورگر دکمه را پیش از تابع پیدا می‌کند و کلیک کاری نمی‌کند. تابع‌های این نمونه خوشامد و نمایش نام دارند. و یادتان باشد بررسی‌هایی مثل این کمک به بازدیدکننده است. سرور باید همین‌ها را دوباره بررسی کند.

قدم بعد. یک خانه‌ی تیک «قوانین را می‌پذیرم» بگذارید که باید زده شود تا دکمه روشن شود. نام را از نظر فقط‌حرف بودن بررسی کنید. نوار قدرت را با عنصر سنجه عوض کنید. فرم را با action و method به نشانی واقعی بفرستید و در سرور بررسی‌اش کنید (بخش آخر را ببینید).

پروژه‌ی ۴: پیشخوان با نمودار میله‌ای CSS

هدف. صفحه‌ای برای نگاه کردن به عددها: چهار کارت آمار، یک نمودار میله‌ای و جدول آخرین سفارش‌ها. بدون هیچ اسکریپتی.

web-project-dashboard.salam
بخش آمار(نام، مقدار، روند، لحن):
    جعبه:
        پس زمینه = سفید فاصله = 18 گردی کادر = 14 سایه کادر = "0 1px 3px rgba(15,23,42,0.1)"
        پاراگراف: محتوا = نام فضا = 0 رنگ = "#64748b" اندازه قلم = "0.85rem" پایان
        پاراگراف: محتوا = مقدار فضا = "4px 0" اندازه قلم = "1.9rem" وزن قلم = پررنگ پایان
        ریز: محتوا = روند رنگ = لحن وزن قلم = 600 پایان
    پایان
پایان

بخش میله(روز، مقدار):
    جعبه:
        فلکس = 1 ترازمتن = وسط
        جعبه: نمایش = فلکس ترازعمودی = "flex-end" چینش = وسط ارتفاع = 150
            جعبه: عرض = "70%" ارتفاع = مقدار + "%" محتوا = مقدار فاصله بالا = 4 رنگ = سفید اندازه قلم = "0.8rem" پس زمینه = "#6366f1" گردی کادر = "8px 8px 0 0" گذار = "background 0.2s" اشاره پس زمینه = "#4338ca" پایان
        پایان
        ریز: محتوا = روز رنگ = "#475569" پایان
    پایان
پایان

بخش نشان(متن، زمینه، نوشته):
    تکه: محتوا = متن فاصله = "2px 10px" گردی کادر = 999 اندازه قلم = "0.8rem" پس زمینه = زمینه رنگ = نوشته پایان
پایان

صفحه:
    عنوان = "پیشخوان فروشگاه"
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 پس زمینه = "#f1f5f9" رنگ = "#0f172a" پایان
    سراسری: گزینشگر = "td, th" فاصله = "10px 8px" ترازمتن = آغاز کادر پایین = "1px solid #e2e8f0" پایان
    سرصفحه: نمایش = فلکس چینش = "space-between" ترازعمودی = وسط فاصله = "16px 5vw" پس زمینه = "#0f172a" رنگ = سفید
        قوی: محتوا = "فندق و شرکا" پایان
        ریز: محتوا = "هفته‌ی ۴۳" رنگ = "#94a3b8" پایان
    پایان
    اصلی: فاصله = "24px 5vw" نمایش = شبکه شکاف = 20
        جعبه: نمایش = شبکه ستون های شبکه = "repeat(auto-fit, minmax(180px, 1fr))" شکاف = 16
            آمار: نام = "درآمد" مقدار = "۸٬۴۲۰ هزار" روند = "۱۲٪ بیشتر از هفته‌ی پیش" لحن = "#15803d" پایان
            آمار: نام = "سفارش‌ها" مقدار = "۳۱۲" روند = "۵٪ بیشتر" لحن = "#15803d" پایان
            آمار: نام = "مرجوعی‌ها" مقدار = "۹" روند = "۲ مورد کمتر از شنبه" لحن = "#15803d" پایان
            آمار: نام = "پیام‌های بی‌پاسخ" مقدار = "۱۴" روند = "۶ مورد بیشتر از شنبه" لحن = "#b91c1c" پایان
        پایان
        جعبه: نمایش = شبکه ستون های شبکه = "repeat(auto-fit, minmax(300px, 1fr))" شکاف = 16
            بخش: پس زمینه = سفید فاصله = 18 گردی کادر = 14
                سرتیتر: اندازه = 2 محتوا = "سفارش‌ها در هر روز" اندازه قلم = "1.1rem" فضا = "0 0 12px 0" پایان
                جعبه: نمایش = فلکس شکاف = 8
                    میله: روز = "ش" مقدار = 45 پایان
                    میله: روز = "ی" مقدار = 62 پایان
                    میله: روز = "د" مقدار = 38 پایان
                    میله: روز = "س" مقدار = 80 پایان
                    میله: روز = "چ" مقدار = 95 پایان
                    میله: روز = "پ" مقدار = 70 پایان
                    میله: روز = "ج" مقدار = 30 پایان
                پایان
            پایان
            بخش: پس زمینه = سفید فاصله = 18 گردی کادر = 14 سرریز = خودکار
                سرتیتر: اندازه = 2 محتوا = "آخرین سفارش‌ها" اندازه قلم = "1.1rem" فضا = "0 0 12px 0" پایان
                جدول: عرض = "100%" ادغام کادر = "collapse"
                    سرصفحه: ردیف: ستون: محتوا = "سفارش" پایان ستون: محتوا = "مشتری" پایان ستون: محتوا = "وضعیت" پایان پایان پایان
                    اصلی:
                        ردیف: سلول: محتوا = "#۲۰۴۱" پایان سلول: محتوا = "مینا رحیمی" پایان سلول: نشان: متن = "ارسال شد" زمینه = "#dcfce7" نوشته = "#166534" پایان پایان پایان
                        ردیف: سلول: محتوا = "#۲۰۴۰" پایان سلول: محتوا = "تام بکر" پایان سلول: نشان: متن = "در حال بسته‌بندی" زمینه = "#fef3c7" نوشته = "#92400e" پایان پایان پایان
                        ردیف: سلول: محتوا = "#۲۰۳۹" پایان سلول: محتوا = "لنا نواک" پایان سلول: نشان: متن = "بازپرداخت شد" زمینه = "#fee2e2" نوشته = "#991b1b" پایان پایان پایان
                    پایان
                پایان
            پایان
        پایان
    پایان
پایان

شرح. نمودار از جعبه‌ها ساخته شده است. میله بخشی است با یک روز و یک مقدار. درونش یک مسیر با ارتفاع ثابت (۱۵۰ پیکسل، یک ظرف فلکس که عنصرهایش با ترازعمودی = "flex-end" ته آن می‌نشینند) و در مسیر جعبه‌ای با ارتفاع = مقدار + "%" هست. مقدار ۸۰ جعبه‌ای می‌دهد که ۸۰ درصد مسیر است. گذاشتن ارتفاع در مسیری با اندازه‌ی معلوم ترفند کار است: ارتفاع درصدی به والدی نیاز دارد که ارتفاعش معلوم باشد. عدد درون میله نوشته شده، پس نمودار را صفحه‌خوان هم می‌خواند، و میله هنگام اشاره رنگ تیره‌تر می‌گیرد. آمارها بخش آمار هستند و برچسب‌های رنگی وضعیت در جدول نشان، بخشی که فقط یک تکه است.

چیدمان دو شبکه‌ی تودرتو است. کارت‌ها auto-fit با کمینه‌ی ۱۸۰ پیکسل دارند و ردیف پایین کمینه‌ی ۳۰۰، پس نمودار و جدول وقتی جا هست کنار هم‌اند و وقتی نیست زیر هم. جدول یک جدول واقعی با بخش‌های سرصفحه و اصلی است و کارتش سرریز = خودکار دارد، پس روی صفحه‌ی باریک جدول درون کارتش اسکرول می‌شود و صفحه را خراب نمی‌کند. قاعده‌ی سراسری td, th به همه‌ی خانه‌ها فاصله‌ی یکسان و یک خط نازک پایین می‌دهد. رنگ اینجا معنا دارد، سبز برای خوب و قرمز برای بد، پس هر رقم نشانه یا کلمه‌ای هم دارد: هرگز نگذارید رنگ تنها پیام باشد.

قدم بعد. میله‌ها را هنگام باز شدن صفحه با یک پویانمایی CSS بالا بیاورید (گذار و پویانمایی). ستونی از دکمه‌ها بگذارید که جدول را پالایش کنند، با الگوی پروژه‌ی ۵. عددها را به‌جای متن برنامه از سرور بگیرید، مثل بخش آخر.

پروژه‌ی ۵: فهرست کاری که به یاد می‌ماند

هدف. یک برنامه‌ی کوچک: کار اضافه کردن، تیک زدن، برداشتن، پالایش با همه، باقی‌مانده و انجام‌شده، شمردن آنچه مانده، و پیدا کردن فهرست پس از بار دوباره.

web-project-todo.salam
واردسازی دام

ناپایا نوشته‌ها := وکتور {} برگردان وکتور<رشته>
ناپایا انجام‌شده‌ها := وکتور {} برگردان وکتور<منطقی>
ناپایا حالت := 0

تابع گزینش(شرط: منطقی، آری: رشته، نه: رشته): رشته:
    اگر شرط:
        برگشت آری
    پایان
    برگشت نه
پایان

تابع نگهدار:
    ناپایا پیوسته := ""
    تکرار نوشته‌ها.طول() در ردیف:
        پیوسته += گزینش(انجام‌شده‌ها.بگیر(ردیف)، "1"، "0") + نوشته‌ها.بگیر(ردیف) + "\n"
    پایان
    دام.تنظیم متن ذخیره("todos"، پیوسته)
پایان

تابع ترسیم:
    نگهدارنده := دام.با شناسه("items")
    دام.تنظیم اچ تی ام ال(نگهدارنده، "")
    ناپایا باز := 0
    تکرار نوشته‌ها.طول() در ردیف:
        اگر وارونه انجام‌شده‌ها.بگیر(ردیف):
            باز += 1
        پایان
        اگر حالت == 0 یا (حالت == 1 و وارونه انجام‌شده‌ها.بگیر(ردیف)) یا (حالت == 2 و انجام‌شده‌ها.بگیر(ردیف)):
            سطر := دام.بساز("li")
            تیک := دام.بساز("input")
            دام.تنظیم ویژگی(تیک، "type"، "checkbox")
            دام.تنظیم خاصیت منطقی(تیک، "checked"، انجام‌شده‌ها.بگیر(ردیف))
            دام.هنگام رویداد(تیک، "change"، (): انجام‌شده‌ها.تنظیم(ردیف، وارونه انجام‌شده‌ها.بگیر(ردیف)) نگهدار() ترسیم() پایان)
            عبارت := دام.بساز("span")
            دام.تنظیم متن(عبارت، نوشته‌ها.بگیر(ردیف))
            دام.تنظیم ویژگی(عبارت، "class"، گزینش(انجام‌شده‌ها.بگیر(ردیف)، "words done"، "words"))
            حذف := دام.بساز("button")
            دام.تنظیم متن(حذف، "x")
            دام.هنگام رویداد(حذف، "click"، (): نوشته‌ها.حذف در(ردیف) انجام‌شده‌ها.حذف در(ردیف) نگهدار() ترسیم() پایان)
            دام.افزودن(سطر، تیک)
            دام.افزودن(سطر، عبارت)
            دام.افزودن(سطر، حذف)
            دام.افزودن(نگهدارنده، سطر)
        پایان
    پایان
    دام.تنظیم متن(دام.با شناسه("left")، "" + باز + " کار مانده")
    تکرار 3 در k:
        دام.تنظیم ویژگی(دام.با شناسه("f" + k)، "class"، گزینش(k == حالت، "pick on"، "pick"))
    پایان
پایان

تابع همگی:
    اگر نوشته‌ها.طول() == 0:
        خط‌ها := دام.دریافت متن ذخیره("todos").بشکاف("\n")
        تکرار خط‌ها.طول() - 1 در ردیف:
            نوشته‌ها.بیفزا(خط‌ها.بگیر(ردیف).زیررشته(1، خط‌ها.بگیر(ردیف).طول()))
            انجام‌شده‌ها.بیفزا(خط‌ها.بگیر(ردیف).زیررشته(0، 1) == "1")
        پایان
    پایان
    حالت = 0
    ترسیم()
پایان

تابع ثبت(رویداد: صحیح۶۴):
    دام.جلوگیری پیش فرض(رویداد)
    متن := دام.دریافت مقدار(دام.با شناسه("new"))
    اگر متن.طول() > 0:
        نوشته‌ها.بیفزا(متن)
        انجام‌شده‌ها.بیفزا(نادرست)
        دام.تنظیم مقدار(دام.با شناسه("new")، "")
        نگهدار()
        ترسیم()
    پایان
پایان

صفحه:
    عنوان = "کارها"
    ظاهر سفارشی: محتوا = ".pick { border: 0; background: none; padding: 4px 10px; border-radius: 6px; cursor: pointer; font-family: inherit } .pick.on { background: #e0e7ff; color: #3730a3 } .words { flex: 1; padding: 0 10px } .words.done { text-decoration: line-through; color: #94a3b8 } li { display: flex; align-items: center; padding: 10px 4px; border-bottom: 1px solid #e2e8f0 } li button { border: 0; background: none; color: #94a3b8; cursor: pointer } li button:hover { color: #dc2626 }" پایان
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 پس زمینه = "#f8fafc" پایان
    اصلی: بیشینه عرض = "28rem" فضا = "28px auto" فاصله = 24 پس زمینه = سفید گردی کادر = 16 سایه کادر = "0 8px 24px rgba(15,23,42,0.08)"
        سرتیتر: اندازه = 1 محتوا = "کارها" اندازه قلم = "1.8rem" فضا = "0 0 14px 0" پایان
        فرم: ارسال = ثبت نمایش = فلکس شکاف = 8
            ورودی: شناسه = "new" جانگهدار = "یک کار تازه بنویسید" فلکس = 1 فاصله = 10 کادر = "2px solid #e2e8f0" گردی کادر = 8 اندازه قلم = "1rem" پایان
            دکمه: نوع = ارسال محتوا = "افزودن" فاصله = "0 18px" کادر = 0 گردی کادر = 8 پس زمینه = "#4f46e5" رنگ = سفید نشانگر = اشاره‌گر خانواده قلم = inherit پایان
        پایان
        فهرست: شناسه = "items" سبک فهرست = هیچ فاصله = 0 فضا = "12px 0" پایان
        جعبه: نمایش = فلکس چینش = "space-between" ترازعمودی = وسط رنگ = "#64748b" اندازه قلم = "0.9rem"
            تکه: شناسه = "left" محتوا = "0 کار مانده" پایان
            جعبه:
                دکمه: شناسه = "f0" کلاس = "pick on" کلیک = همگی محتوا = "همه" پایان
                دکمه: شناسه = "f1" کلاس = "pick" کلیک = (): حالت = 1 ترسیم() پایان محتوا = "باقی‌مانده" پایان
                دکمه: شناسه = "f2" کلاس = "pick" کلیک = (): حالت = 2 ترسیم() پایان محتوا = "انجام‌شده" پایان
            پایان
        پایان
    پایان
    اسکریپت سفارشی: محتوا = "window.addEventListener('DOMContentLoaded', function () { همگی(); });" پایان
پایان

شرح. این الگوی حالت در اندازه‌ی کامل است. حالت سه متغیر سطح بالاست: نوشته‌ها و انجام‌شده‌ها، دو وکتور که متن و نشان انجام‌شدن هر کار را نگه می‌دارند، و حالت، پالایه. صفحه چیز دیگری به یاد ندارد. ترسیم فهرست را خالی می‌کند، وکتورها را می‌گذراند و برای هر کاری که از پالایه می‌گذرد ردیفی می‌سازد، و باقی‌مانده‌ها را می‌شمارد. هر تغییر، یعنی افزودن، تیک زدن، برداشتن و پالایش، با صدا زدن ترسیم تمام می‌شود، پس یک جا هست که صفحه ساخته می‌شود. دوباره ساختن کل فهرست کمی اسراف است و بسیار ایمن. برای فهرستی از چند صد کار کسی تفاوت را نمی‌فهمد.

رویدادگیر ردیف‌ها هنگام اجرا با دام.هنگام رویداد ساخته می‌شوند و هر لامبدا ردیف خودش را به یاد دارد، پس تیک ردیف سوم کار سوم را عوض می‌کند. پس از هر تغییر ردیف‌ها دوباره ساخته می‌شوند و این شماره‌ها هیچ‌وقت کهنه نیستند. ذخیره نگهدار است: یک رشته می‌نویسد، یک سطر برای هر کار، با 1 یا 0 پیش از متن که می‌گوید انجام شده یا نه. بارگذاری عکس آن است، در همگی که رویدادگیر دکمه‌ی «همه» هم هست؛ عنصر script در آخرین سطر آن را پس از خوانده شدن صفحه صدا می‌زند، مثل بخش ذخیره‌سازی. سلام اگر درون‌خطی ندارد، پس تابع کوچک گزینش یکی از دو رشته را برمی‌دارد و بقیه‌ی کد را کوتاه نگه می‌دارد.

پیش‌نمایش در قابی اجرا می‌شود که ذخیره‌سازی را اجازه نمی‌دهد، پس آنجا فهرست کار می‌کند اما پس از بار دوباره نمی‌ماند. در صفحه‌ی واقعی می‌ماند. متن کار همیشه با تنظیم متن گذاشته می‌شود، هرگز تنظیم اچ تی ام ال.

قدم بعد. با دو کلیک ویرایش کار را ممکن کنید. دکمه‌ی «پاک کردن انجام‌شده‌ها» بگذارید. زمان ساخته شدن را ذخیره کنید و بر اساس آن مرتب کنید. ذخیره را به سرور ببرید تا فهرست همراه شخص به دستگاه دیگری برود.

هدف. یک شبکه از تصویرها. با کلیک روی هر کدام در پنجره‌ای بزرگ باز می‌شود، با دکمه‌های قبلی، بعدی و بستن، و کلیدهای جهت و Escape هم کار می‌کنند. تصویرهای اینجا گرادیان‌اند، پس صفحه به هیچ پرونده‌ای نیاز ندارد و کد برای عکس واقعی هم همین است.

web-project-gallery.salam
واردسازی دام

ناپایا فعلی := 0 برگردان صحیح۶۴

تابع نمایش‌عکس(شماره: صحیح۶۴):
    کاشی‌ها := دام.پرسمان همه("[data-n]")
    کل := دام.تعداد(کاشی‌ها)
    فعلی = (شماره + کل) % کل
    کاشی := دام.عنصر شماره(کاشی‌ها، فعلی)
    دام.تنظیم سبک(دام.با شناسه("big")، "background"، دام.دریافت ویژگی(کاشی، "data-bg"))
    دام.تنظیم متن(دام.با شناسه("cap")، دام.دریافت ویژگی(کاشی، "data-title") + " (" + (فعلی + 1) + " از " + کل + ")")
پایان

تابع بازکردن(رویداد: صحیح۶۴):
    نمایش‌عکس(دام.دریافت ویژگی(دام.هدف رویداد(رویداد)، "data-n").به صحیح() برگردان صحیح۶۴)
    _باز := دام.فراخوان(دام.با شناسه("lightbox")، "showModal")
پایان

تابع بستن:
    _بسته := دام.فراخوان(دام.با شناسه("lightbox")، "close")
پایان

تابع کلیدها(رویداد: صحیح۶۴):
    اگر دام.کلید رویداد(رویداد) == "ArrowRight":
        نمایش‌عکس(فعلی - 1)
    وگرنه دام.کلید رویداد(رویداد) == "ArrowLeft":
        نمایش‌عکس(فعلی + 1)
    پایان
پایان

تابع پشت‌پرده(رویداد: صحیح۶۴):
    اگر دام.هدف رویداد(رویداد) == دام.با شناسه("lightbox"):
        بستن()
    پایان
پایان

بخش عکس(شماره، نام، روشن، تیره):
    دکمه:
        داده n = شماره داده title = نام داده bg = "linear-gradient(135deg, " + روشن + ", " + تیره + ")" کلیک = بازکردن
        پس زمینه = "linear-gradient(135deg, " + روشن + ", " + تیره + ")" محتوا = نام نسبت ابعاد = "4 / 3" کادر = 0 گردی کادر = 12
        رنگ = سفید اندازه قلم = "1rem" وزن قلم = 600 ترازمتن = آغاز فاصله = 12 نشانگر = اشاره‌گر گذار = "transform 0.15s" خانواده قلم = inherit
        اشاره دگرگونی = "scale(1.04)"
    پایان
پایان

صفحه:
    عنوان = "آلبوم سفر"
    ظاهر سفارشی: محتوا = "dialog { border: 0; border-radius: 16px; padding: 16px; width: min(34rem, 92vw) } dialog::backdrop { background: rgba(15, 23, 42, 0.7) } .bar button { padding: 8px 16px; border: 0; border-radius: 8px; background: #e2e8f0; cursor: pointer; font-family: inherit } .bar button:hover { background: #cbd5e1 }" پایان
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 فاصله = "24px 5vw" پس زمینه = "#0f172a" رنگ = سفید پایان
    سرتیتر: اندازه = 1 محتوا = "سفر به کویر" اندازه قلم = "1.8rem" فضا = "0 0 16px 0" پایان
    جعبه: نمایش = شبکه ستون های شبکه = "repeat(auto-fill, minmax(150px, 1fr))" شکاف = 12
        عکس: شماره = 0 نام = "طلوع" روشن = "#f97316" تیره = "#facc15" پایان
        عکس: شماره = 1 نام = "چادر" روشن = "#7c3aed" تیره = "#ec4899" پایان
        عکس: شماره = 2 نام = "تپه‌ها" روشن = "#d97706" تیره = "#fde68a" پایان
        عکس: شماره = 3 نام = "واحه" روشن = "#059669" تیره = "#67e8f9" پایان
        عکس: شماره = 4 نام = "ستاره‌ها" روشن = "#1e1b4b" تیره = "#6366f1" پایان
        عکس: شماره = 5 نام = "راه برگشت" روشن = "#475569" تیره = "#cbd5e1" پایان
    پایان
    پنجره گفتگو: شناسه = "lightbox" فشردن کلید = کلیدها کلیک = پشت‌پرده رنگ = "#0f172a"
        جعبه: شناسه = "big" ارتفاع = 260 گردی کادر = 12 پایان
        پاراگراف: شناسه = "cap" فضا = "12px 0" وزن قلم = 600 پایان
        جعبه: کلاس = "bar" نمایش = فلکس شکاف = 8
            دکمه: شناسه = "back" کلیک = (): نمایش‌عکس(فعلی - 1) پایان محتوا = "قبلی" پایان
            دکمه: شناسه = "forth" کلیک = (): نمایش‌عکس(فعلی + 1) پایان محتوا = "بعدی" پایان
            دکمه: شناسه = "shut" کلیک = بستن محتوا = "بستن" فضا چپ = خودکار پایان
        پایان
    پایان
پایان

شرح. پنجره یک عنصر پنجره گفتگو (dialog) است. صدا زدن showModal روی آن، با دام.فراخوان(پنجره، "showModal")، آن را روی همه‌چیز می‌آورد، صفحه‌ی پشتش را تیره می‌کند، فوکوس صفحه‌کلید را به درونش می‌برد و با Escape می‌بندد. همه‌ی اینها از مرورگر می‌آید. لایه‌ی تیره با dialog::backdrop در یک عنصر style سبک می‌خورد. کلیک روی پس‌زمینه کلیک روی خود پنجره حساب می‌شود، پس رویدادگیر پشت‌پرده وقتی پنجره را می‌بندد که دام.هدف رویداد(رویداد) خود پنجره باشد و نه یکی از فرزندانش. (کلیک روی فاصله‌ی داخلی خود پنجره هم حساب می‌شود، پس فاصله را کم نگه دارید.)

هر کاشی یک دکمه از بخش عکس است و دکمه داده‌اش را در ویژگی‌ها دارد: داده n، داده title و داده bg. یک رویدادگیر، بازکردن، به هر شش کاشی خدمت می‌کند. از رویداد می‌پرسد کدام دکمه زده شد و ویژگی‌ها را می‌خواند، و نمایش‌عکس آن‌ها را در پنجره می‌ریزد. قبلی و بعدی نمایش‌عکس را با یکی کمتر یا بیشتر صدا می‌زنند و % در (شماره + کل) % کل از آخرین عکس به اولین می‌پیچد. کلیدهای جهت در صفحه‌ی راست‌به‌چپ برعکس‌اند: کلید راست یعنی «قبلی»، چون قبلی سمت راست است. کاشی‌ها با پرسمان همه("[data-n]") پیدا می‌شوند و نه با کلاس. دو عنصر با یک کلاس باید یکسان باشند و هر کاشی گرادیان خودش را دارد، پس مترجم کلاس مشترک را رد می‌کرد (خطای E136).

قدم بعد. تصویرهای واقعی در کاشی‌ها بگذارید (پیوند، تصویر و رسانه) و از هر کدام یک نسخه‌ی کوچک و یک نسخه‌ی بزرگ نگه دارید. با کشیدن به پایین پنجره را ببندید. فوکوس را به کاشی‌ای که پنجره را باز کرد برگردانید.

فرستادن صفحه از یک برنامه‌ی سلام

همه‌ی آنچه بالا آمد صفحه‌ی ثابت است: ساختارش هنگام ترجمه معلوم می‌شود و پیش‌نمایش نتیجه‌ی نهایی است. سایت واقعی صفحه‌هایی لازم دارد که به بازدیدکننده بستگی داشته باشند، مثل خوشامدی با نام او یا پیشخوانی با عددهای امروز. برای این، صفحه نام و پارامتر می‌گیرد و تابعی می‌شود که صفحه را به شکل HTML برمی‌گرداند. سرور وب نوشته‌شده به سلام آن را برای هر درخواست صدا می‌زند. نخستین درس این بخش این صفحه‌ها را به تفصیل می‌گوید؛ اینجا کوچک‌ترین برنامه‌ی کامل است، که صفحه‌ای را با نام و طرحی که از نشانی می‌گیرد می‌فرستد.

web-project-serve.salam
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.مسیریاب

صفحه خوشامد(نام: رشته، طرح: رشته):
    عنوان = "خوش آمدید " + نام
    زبان = "فارسی"
    جهت = "راست به چپ"
    سراسری: گزینشگر = "body" خانواده قلم = "Tahoma, system-ui, sans-serif" فضا = 0 پس زمینه = "#fafaf9" پایان
    اصلی: بیشینه عرض = "30rem" فضا = "48px auto" فاصله = 28 پس زمینه = سفید گردی کادر = 16
        سرتیتر: اندازه = 1 محتوا = "خوش آمدید " + نام پایان
        پاراگراف: محتوا = "طرح " + طرح + " شما از دوشنبه شروع می‌شود." پایان
    پایان
پایان

تابع خانه(زمینه: صحیح۶۴):
    ناپایا نام := اچ تی تی پی.پرسمان(زمینه، "name")
    ناپایا طرح := اچ تی تی پی.پرسمان(زمینه، "plan")
    اگر نام == "":
        نام = "دوست عزیز"
    پایان
    اگر طرح == "":
        طرح = "تکی"
    پایان
    اچ تی تی پی.اچ تی ام ال(زمینه، خوشامد(نام، طرح))
پایان

تابع ریشه:
    ناپایا م := مسیریاب.مسیریاب جدید()
    مسیریاب.دریافت(م، "/"، خانه)
    ناپایا س := اچ تی تی پی.سرور جدید(۸۰۸۰)
    اچ تی تی پی.استفاده(س، م)
    اچ تی تی پی.اجرا(س)
پایان

برنامه سرور را راه می‌اندازد و خروجی ندارد، پس اینجا فقط بررسی می‌شود. اجرایش کنید، http://localhost:8080/?name=Ada&plan=Duo را باز کنید و صفحه را می‌بینید. متنی که در پارامتر می‌رسد برایتان خنثی‌سازی می‌شود، پس بازدیدکننده‌ای که ?name=<b> بفرستد نویسه‌ها را می‌بیند و هیچ نشانه‌گذاری‌ای نه. برای سمت سرور، بسته‌های net.http و net.router درخواست و پرسش‌های نشانی و پاسخ را مدیریت می‌کنند و net/http/validate داده‌ی فرمی را که پروژه‌ی ۳ در مرورگر گرفت بررسی می‌کند. صفحه‌ی ثابت، مثل پروژه‌های ۱ تا ۶، هم همان‌طور که هست کامل است: salam page build page.salam --inline آن را در یک پرونده‌ی HTML می‌نویسد که هر میزبان وبی می‌فرستدش.

خودتان امتحان کنید

  • دو پروژه را با هم ترکیب کنید. به صفحه‌ی فرود، زیر طرح‌ها، فرم عضویت پروژه‌ی ۳ را بدهید و دکمه‌های انتخاب را وادار کنید نام طرح را در فرم بنویسند.
  • نوشته‌ی وبلاگ را به صفحه‌ای دوباره‌به‌کاربردنی تبدیل کنید: بخشی به نام نوشته با یک عنوان و یک تاریخ، و دو نوشته که از آن استفاده می‌کنند. کدام قسمت‌ها ثابت می‌مانند و کدام پارامتر می‌شوند؟
  • پیشخوان را روی تلفن ببرید: پیش‌نمایش را در پنجره‌ای باریک باز کنید و هر چه تنگ است را فقط با auto-fit و یک قاعده‌ی رسانه درست کنید.
  • یک پروژه را به انگلیسی ترجمه کنید. کدام ویژگی‌های سبک برای صفحه‌ی چپ‌به‌راست باید عوض شوند و کدام خودشان عوض می‌شوند؟