{"id":6119,"date":"2026-04-28T13:42:43","date_gmt":"2026-04-28T06:42:43","guid":{"rendered":"https:\/\/dev.artru.net\/?p=6119"},"modified":"2026-04-28T13:52:42","modified_gmt":"2026-04-28T06:52:42","slug":"tong-hop-css-thay-the-javascript","status":"publish","type":"post","link":"https:\/\/artru.net\/en\/tong-hop-css-thay-the-javascript\/","title":{"rendered":"Goodbye JavaScript: A compilation of CSS features to replace JS in 2026"},"content":{"rendered":"<h2 class=\"wp-block-heading\">Popover API: Create pop-ups and dialogs without JavaScript.<\/h2>\n\n\n\n<p>Previously, to create a modal window or menu, you needed JavaScript to handle events. <code data-no-translation=\"\" data-no-auto-translation=\"\">click<\/code>, state management <code data-no-translation=\"\" data-no-auto-translation=\"\">display: block\/none<\/code> and handles closing when clicked outside. The Popover API handles all of this automatically.<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">&lt;button popovertarget=\"info-box\">Xem chi ti\u1ebft&lt;\/button>\n\n&lt;div id=\"info-box\" popover>\n  &lt;h3>Th\u00f4ng b\u00e1o quan tr\u1ecdng&lt;\/h3>\n  &lt;p>B\u1ea1n \u0111\u00e3 m\u1edf pop-up n\u00e0y ho\u00e0n to\u00e0n b\u1eb1ng CSS!&lt;\/p>\n  &lt;button popovertarget=\"info-box\" popovertargetaction=\"hide\">\u0110\u00f3ng&lt;\/button>\n&lt;\/div><\/code><\/pre>\n\n\n\n<p><strong>Advantage:<\/strong> Automatic key support <code data-no-translation=\"\" data-no-auto-translation=\"\">Esc<\/code> to close and mechanism <code data-no-translation=\"\" data-no-auto-translation=\"\">\"Light Dismiss\"<\/code> (Press outside to close).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Anchor Positioning: Positioning Tooltips and Dropdowns<\/h2>\n\n\n\n<p>One of the biggest reasons we use JS (as a library) is... <code data-no-translation=\"\" data-no-auto-translation=\"\">Popper.js<\/code> nice <code data-no-translation=\"\" data-no-auto-translation=\"\">Floating UI<\/code>) is used to calculate the position of the dropdown menu so that it does not overflow the screen. <code data-no-translation=\"\" data-no-auto-translation=\"\">Anchor Positioning<\/code> It is an alternative solution.<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">\/* G\u00e1n t\u00ean cho ph\u1ea7n t\u1eed g\u1ed1c *\/\n.anchor-button {\n  anchor-name: --nav-menu;\n}\n\n\/* K\u1ebft n\u1ed1i menu v\u1edbi n\u00fat g\u1ed1c *\/\n.dropdown-menu {\n  position: absolute;\n  position-anchor: --nav-menu;\n  \/* \u0110\u1ecbnh v\u1ecb: N\u1eb1m d\u01b0\u1edbi n\u00fat v\u00e0 c\u0103n l\u1ec1 ph\u1ea3i *\/\n  position-area: bottom span-right;\n  margin-top: 8px;\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Scroll-driven Animations: Smooth page scrolling effects<\/h2>\n\n\n\n<p>Creating progress bar effects when scrolling or parallax effects often consumes a lot of JS resources (because it has to listen for scroll events). <code data-no-translation=\"\" data-no-auto-translation=\"\">scroll<\/code> (continuously). CSS now has <code data-no-translation=\"\" data-no-auto-translation=\"\">scroll-timeline<\/code>.<\/p>\n\n\n\n<p>Example: Article reading progress bar<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">@keyframes grow-progress {\n  from { transform: scaleX(0); }\n  to { transform: scaleX(1); }\n}\n\n.progress-bar {\n  position: fixed;\n  top: 0; left: 0;\n  width: 100%; height: 5px;\n  background: gold;\n  transform-origin: 0 50%;\n  \/* Li\u00ean k\u1ebft animation v\u1edbi vi\u1ec7c cu\u1ed9n trang *\/\n  animation: grow-progress auto linear;\n  animation-timeline: scroll();\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Container Queries: Replace Media Queries for Component<\/h2>\n\n\n\n<p>Instead of changing the interface based on screen size (Media Queries), we can change it based on the size of the container itself. This makes components more flexible without needing to use `&lt;div&gt;`. <code data-no-translation=\"\" data-no-auto-translation=\"\">ResizeObserver<\/code> in JS.<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">.container {\n  container-type: inline-size;\n}\n\n\/* Khi container r\u1ed9ng h\u01a1n 500px, chuy\u1ec3n sang giao di\u1ec7n 2 c\u1ed9t *\/\n@container (min-width: 500px) {\n  .card {\n    display: flex;\n    gap: 20px;\n  }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclude<\/h2>\n\n\n\n<p>The shift from JS to CSS isn&#039;t just a trend; it&#039;s about optimizing the end-user experience. By utilizing built-in browser features, you can make websites load faster, smoother, and minimize script conflicts.<\/p>\n\n\n\n<p>Reference source:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"7 CSS Tricks That Will Blow Your Mind\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/Ol62e-dWu0E?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>","protected":false},"excerpt":{"rendered":"<p>Popover API: L\u00e0m Pop-up v\u00e0 Dialog kh\u00f4ng c\u1ea7n JS Tr\u01b0\u1edbc \u0111\u00e2y, \u0111\u1ec3 l\u00e0m m\u1ed9t c\u1eeda s\u1ed5 modal hay menu, b\u1ea1n c\u1ea7n JS \u0111\u1ec3 b\u1eaft s\u1ef1 ki\u1ec7n click, qu\u1ea3n l\u00fd tr\u1ea1ng [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[113],"tags":[],"class_list":["post-6119","post","type-post","status-publish","format-standard","hentry","category-css"],"_links":{"self":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/posts\/6119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/comments?post=6119"}],"version-history":[{"count":0,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/posts\/6119\/revisions"}],"wp:attachment":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/media?parent=6119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/categories?post=6119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/tags?post=6119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}