PROJECT 0 KB
Изключих JavaScript. Сайтът не умря.
Нека започна с провокация. Уебът не е станал тежък само защото задачите са тежки. Станал е тежък и защото сме си изградили рефлекс: виждаме бутон, меню или модален прозорец и още преди браузърът да е казал последната си дума, вече сме отворили package manager-а. Инсталираме библиотека, добавяме listener, местим класове по DOM дървото и накрая празнуваме, че един панел се отваря.
Този път направих обратното. Забраних JavaScript напълно и си зададох прост въпрос: колко истински интерфейс може да остане, ако клиентът не получи нито един байт JavaScript? Не макет. Не картинка. Работещ сайт, който може да бъде използван с мишка и клавиатура.
CSS не е заменил JavaScript. Браузърът просто си върна част от работата, която години наред го карахме да върши чрез чужд код.
▶ ОТВОРИ ЖИВОТО ZERO-JS ДЕМО
После отвори DevTools, Network, филтрирай по JS и презареди страницата.
После отвори DevTools, Network, филтрирай по JS и презареди страницата.
01. Лабораторният договор
За да има смисъл експериментът, правилата са без вратички. Няма
<script> елементи, няма inline обработчици като onclick, няма JavaScript заявки и няма библиотека, която тайно да свърши работата. HTML носи смисъла и поведението, CSS носи представянето и визуалното състояние, а браузърът поема функциите, които вече познава нативно.Има и още едно правило. Достъпността не е декоративна отметка. Фокусът трябва да се вижда, Escape трябва да затваря временните слоеве, диалогът трябва да задържа фокуса правилно, а при
prefers-reduced-motion движенията трябва да бъдат ограничени. Ако един трик работи само с мишка върху моя монитор, това не е интерфейс. Това е номер за парти.02. Popover без listener
Преди време за малък панел пишехме функция за отваряне, функция за затваряне, listener за Escape, listener за клик извън елемента и логика за слой над останалото съдържание. Днес Popover API дава голяма част от това поведение декларативно. Бутонът посочва целта, елементът носи атрибута
popover, а браузърът управлява top layer, light dismiss и клавиатурното затваряне.
HTML:
<button popovertarget="lab-menu">
Отвори менюто
</button>
<div id="lab-menu" popover>
<strong>Нативен канал отворен</strong>
<p>Този панел се появи без JavaScript.</p>
<button
popovertarget="lab-menu"
popovertargetaction="hide">
Затвори
</button>
</div>
Тук няма магия и няма скрит listener. Връзката между контролата и панела е описана в самия HTML. Това е важната промяна в мисленето: когато поведението вече има семантичен модел в платформата, не е нужно да го симулираме с произволни
div елементи и класове.03. Dialog, управляван от HTML
Модалният прозорец в демото се отваря чрез Invoker Commands API. Атрибутът
commandfor сочи кой елемент управляваме, а command="show-modal" казва какво искаме от него. Самият <dialog> остава истински диалог, а не кутия с огромен z-index, която се преструва на такъв.
HTML:
<button
type="button"
commandfor="proof-dialog"
command="show-modal">
Отвори доказателството
</button>
<dialog id="proof-dialog">
<h2>JavaScript отсъства.</h2>
<form method="dialog">
<button value="verified">Затвори</button>
</form>
</dialog>
Браузърът отваря модалния режим, прави фона неактивен, управлява фокуса и приема Escape. Формата с
method="dialog" затваря прозореца нативно.Два капана, които струват време. Първо,
command и commandfor работят само върху <button>, не върху връзка или div. Второ, ако commandfor сочи към несъществуващо id, нищо не се случва и никъде не пише грешка.Това не означава, че диалоговите системи никога повече няма да имат нужда от JavaScript. Означава, че базовата механика вече не е наша работа.
04. :has() и родителят, който вече вижда промяната
Следващият стар навик е добавянето и махането на класове само за да покажем състояние. В демото темата се сменя от обикновен checkbox. CSS вижда, че той е маркиран, и променя променливите на страницата. Няма
document.querySelector(), няма classList.toggle().
HTML:
<input id="light-mode" type="checkbox">
<label for="light-mode">Смени темата</label>
CSS:
body:has(#light-mode:checked) {
color-scheme: light;
--bg: #edf3f7;
--panel: #ffffff;
--ink: #17222b;
}
Същата идея захранва checklist-а. Всеки маркиран ред променя собствения си вид, а когато четирите проверки са изпълнени, финалният статус се появява. Това е състояние, но е малко, локално и живее естествено в HTML. Няма причина да му строим отделна JavaScript държава с правителство и данъчна администрация.
CSS:
.checklist label:has(input:checked) {
border-color: #57e389;
color: #ffffff;
}
.checklist:has(#c1:checked):has(#c2:checked):has(#c3:checked):has(#c4:checked) .success {
display: block;
}
05. Анимация при скрол без scroll listener
Прогресът в горната част и появата на секциите използват scroll-driven animations. Вместо да слушаме всяко движение на страницата, CSS свързва анимацията със scroll timeline. Функцията е добавена като прогресивно подобрение. Ако браузърът я разбира, я изпълнява. Ако не я разбира, съдържанието остава видимо и използваемо.
CSS:
.scroll-progress {
transform: scaleX(0);
transform-origin: left center;
}
@supports (animation-timeline: scroll()) {
.scroll-progress {
animation: progress linear both;
animation-timeline: scroll(root block);
}
@keyframes progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: .01ms !important;
transition-duration: .01ms !important;
}
}
Редът има значение. Съкратената форма
animation нулира animation-timeline, затова timeline-ът се декларира след нея, а не преди.Това е и правилното място за
@supports. Не питаме кой е браузърът и не гадаем по user agent. Питаме директно дали средата разбира възможността. Ако отговорът е „не“, не наказваме посетителя с празна страница.06. Одитът, числата вместо рекламата
Демото беше проверено в реален браузър, а не само прегледано по код. Тествах отваряне и затваряне, Escape, преместване на фокуса, смяна на темата,
<details>, завършване на checklist-а, responsive ширина и мрежовите ресурси.| Проверка | Резултат |
|---|---|
<script> елементи в документа | 0 |
| Заредени JavaScript ресурси | 0 |
| JavaScript библиотеки | 0 |
| Нативни popover панели | 2 |
| Нативни dialog елементи | 1 |
| Бутони в интерфейса | 8 |
| Затваряне с Escape | ДА |
| Видим клавиатурен фокус | ДА |
| Хоризонтално преливане | НЯМА |
Точното твърдение е 0 B клиентски JavaScript, а не „сайт с нулев размер“. Има HTML, има CSS, има шрифтове от системата и има сървър. Нулата се отнася само за JavaScript, защото техническата честност струва повече от силното заглавие.
07. Какво печелим реално
Когато JavaScript липсва, браузърът няма какво да изтегля, парсва, компилира и изпълнява по тази линия. Няма hydration, няма състезание между markup и bundle, няма framework runtime само за да отвори панел. Това обаче не е автоматичен сертификат за бърз сайт. Огромни изображения, блокиращ CSS, бавен сървър и лош HTML могат спокойно да съсипят и Zero-JS страница.
По-голямата печалба тук е архитектурна. По-малко движещи се части означава по-малко места за дефекти, по-малко зависимости и по-ясна връзка между елемента и поведението му. Когато HTML казва „този бутон управлява този диалог“, намерението се чете от кода без археологическа експедиция из три компонента и пет hook-а.
08. Къде нулата е силна и къде става поза
Zero-JS е силен при навигация, разкриване на съдържание, popover панели, базови диалози, responsive layout, светла и тъмна тема, нативна валидация, локално визуално състояние и прогресивни ефекти. Това е голяма територия, особено за статии, документация, продуктови страници, портфолиа и леки инструменти.
Но ако приложението трябва да синхронизира данни в реално време, да пази сложна клиентска история, да редактира документи, да работи офлайн, да рисува интерактивна визуализация или да координира сериозно състояние между много компоненти, JavaScript не е грях. Той е правилният инструмент.
Нулата не е религия. Тя е контролен въпрос: трябва ли ми скрипт за това, или просто съм свикнал да го пиша?
09. Съвместимост без самозаблуда
Трите стълба на демото не са еднакво зрели и това трябва да се каже направо.
:has() работи във всички основни браузъри от края на 2023 г. и днес е най-стабилният от трите. Popover API влезе в Baseline Newly available на 27 януари 2025 г., след като по-рано беше обявен погрешно заради дефект в iOS. Invoker Commands, тоест command и commandfor, е най-младият. Той стана Baseline Newly available през декември 2025 г., след Chrome 135 и Firefox 144.„Newly available“ не значи „навсякъде“. Значи „във всички актуални версии“. За Popover пълният статус Widely available се очаква чак през 2027 г., а по-старите браузъри нямат нищо общо с това.
Има и практическа последица. При Popover бутонът със
popovertarget в стар браузър просто показва панела като нормален елемент от потока, тоест съдържанието остава четимо. При Invoker Commands бутонът, който не се разбира, не прави нищо, мълчаливо. Затова за критична функционалност или се използва popovertarget, или диалогът остава видима секция от страницата с котва към нея.Не избираме технология по гордост. Избираме я по данни за реалната аудитория.
10. Предизвикателството към DTGaraGe
Отвори демото. Натисни бутоните. Смени темата. Използвай Tab и Escape. После отвори DevTools, филтрирай Network по JS и презареди. Ако намериш JavaScript ресурс, покажи го.
Ако не намериш, направи следващото по-интересно нещо: добави една полезна функция само с HTML и CSS и публикувай кода си в темата.
- Без
<script>елементи - Без inline event handlers
- Без скрит framework runtime
- Посочи браузъра и версията, в която си тествал
Нека превърнем темата не в спор „CSS срещу JavaScript“, а в колективен одит на навиците ни.
Ключови думи: zero javascript, popover api, invoker commands, commandfor, css has, scroll-driven animations, progressive enhancement, baseline, html5, css3, native web, dtgarage
Източници: MDN Popover API, MDN Invoker Commands API, MDN CSS :has(), MDN CSS @supports, web.dev Popover Baseline, web.dev Baseline, Web Platform Features Explorer
- MDN - Popover API
- MDN - Invoker Commands API
- MDN - CSS :has()
- MDN - CSS @supports
- web.dev - Popover API в Baseline
- web.dev - Baseline
toni@dtgarage:~$ whoami
Тони Ангелчовски | Ексклузивно за DTGaraGe
toni@dtgarage:~$ cat LICENSE
Копирането и препубликуването без разрешение не е позволено.
toni@dtgarage:~$ ./support.sh
Подкрепи DTGaraGe и независимото техническо съдържание
toni@dtgarage:~$ █
Тони Ангелчовски | Ексклузивно за DTGaraGe
toni@dtgarage:~$ cat LICENSE
toni@dtgarage:~$ ./support.sh
toni@dtgarage:~$ █
Last edited: