A Language Selector Dropdown With No Framework and No Layout Shift
A language selector sounds like a small job until you ship it on a page where every pixel matters. On ramrom.io I run a video downloader with nine languages and no framework anywhere — plain HTML, a bit of CSS, and vanilla JavaScript. The selector had to let a visitor switch language without the page jumping around, and it had to work on a cheap Android phone on a slow connection. The layout shift problem My first attempt was the obvious one: a element in the header. It worked, but it looked wrong on every device. On desktop it was a grey box that clashed with the blue-and-white theme. On mobile it was wide enough to push the logo onto a second line, and when the language changed, the longer translated strings — German button labels are famously long — shoved the whole header sideways. That sideways shove is a layout shift, and it is exactly the kind of thing that makes a tool page feel cheap. What I built instead The selector is now a plain with a short label — the current language code, like EN — and a tiny chevron drawn in CSS. Clicking it opens a small list of languages positioned absolutely below the button. The list is a with position: absolute, so opening it never moves anything else on the page. The button itself is a fixed width, wide enough for the longest label I ship, so switching from EN to العربية does not change its size either. The translations live in a small JavaScript dictionary: one object per language, keyed by element IDs. Switching language is a loop that walks the dictionary and sets textContent on each element. There is no re-render, no framework diffing, and no network request — the whole dictionary ships inside one small script file, so the switch happens instantly even on a slow connection. A few details that mattered more than I expected: The button keeps its width. I set min-width on it and sized it for the longest label. A button that grows and shrinks every time you change language is a layout shift wearing a disguise. The list closes itself. Clicking outside, pressing Escape, or picking a language all close it. A dropdown that stays open over the download button is worse than no dropdown at all. The choice is remembered. I store the language in localStorage, so a returning visitor sees their language straight away instead of flashing English first and then switching. That flash of the wrong language is another kind of shift, just a visual one. Right-to-left is a real case. Arabic is one of the nine languages, and the page needs dir="rtl" on the element when it is active. The selector button stays put because it is positioned with logical properties rather than fixed left and right values. No webfont for the labels. The language names render in the system font stack. Downloading a font just to spell out nine language names would be a performance cost with no benefit. What I would do differently Honestly, the element is not a bad answer for most sites — it is accessible out of the box, and screen readers understand it perfectly. What I built needs the extra work: aria-expanded on the button, arrow-key navigation through the list, and focus returning to the button when the list closes. If you skip that, you have built a prettier control that some visitors cannot use at all. The lesson I keep coming back to is a boring one: layout shift is not only about images without dimensions. Any element that changes size after the page loads — a language label, a button, a header — can do it. Fixing it usually means reserving the space up front instead of letting the browser discover the size later. That is true for a language selector, and it is true for everything else on a tool page where the visitor's attention is on one button and nothing should move around it.
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to