<select> 에는 placeholder 속성이 없다 — 값이 "" 인 첫 option 을 disabled 로 다시 못 고르게, hidden 으로 목록에서 숨긴다. 필수 입력(required)이면 스펙상 그 option 이 placeholder label option 이 되어, 고르지 않고 제출하면 막힌다.1 React 에서는 <option selected> 대신 <select defaultValue=""> 로 기본 선택한다.2
function Select({ placeholder, children }) {
return (
<select defaultValue="">
<option value="" disabled hidden>
{placeholder}
</option>
{children}
</select>
)
}
Footnotes
-
HTML Standard — the select element: “If a select element has a required attribute specified, and has a display size of 1; and if the value of the first option element in the select element’s list of options (if any) is the empty string, … then that option is the select element’s placeholder label option.” ↩
-
: “Unlike in HTML, passing a
selectedattribute to<option>is not supported. Instead, use<select defaultValue>for uncontrolled select boxes and<select value>for controlled select boxes.” ↩
html
<head />
구조화된 데이터
- Using Structured Data to Enhance Search Engine Optimization | CSS-Tricks
- Understand How Structured Data Works | Google Search Central
lang
favicon
- How to Favicon in 2021: Six files that fit most needs — Martian Chronicles, Evil Martians’ team blog
- How to Create a Favicon That Changes Automatically | CSS-Tricks
- Emojis as Favicons | CSS-Tricks
- We Analyzed 425,909 Favicons • iconmap.io1
Microdata
attributes
Footnotes
-
다양한 관점에서 파비콘을 분석한 글 ↩
자동완성 기능은 편리할수도 있지만 비활성화가 필요한 경우도 있다. 하지만 chrome에서 무시되는 경우가 있는데…이게 거의 된다 지금은 안된다…되는 것 같다…이렇게 변질이 되는 것 같다.
- html - Disabling Chrome Autofill - Stack Overflow1
- Disabling autofill in Chrome | Codementor2
- How to turn off form autocompletion - Web security | MDN
- The Autofill Dark Pattern — Smashing Magazine
Footnotes
blocking=render 는 <body> 전에만 등록된다 — 뒤에 붙으면 조용한 no-op
새로고침하면 한 프레임 동안 스타일이 붙기 전 default 상태가 보인다. 파서를 멈추는 것과 paint를 멈추는 것은 다르다 — 동기 <script>는 파서만 세우고, 그 위에 이미 파싱된 청크가 먼저 그려질지는 브라우저 재량이다. blocking="render"가 paint까지 막는 걸 보장하는데, <body> 뒤에 붙으면 조용히 아무 일도 안 한다.
1. 이 축의 문제인가
| 증상 | 원인 | 처방 |
|---|---|---|
| 스타일이 붙기 전 default 상태가 한 프레임 보인다 | 스타일 적용이 첫 페인트보다 늦다 | blocking="render" — 여기서 계속 |
| 다크 테마인데 흰 화면이 번쩍인다 | 서버가 사용자 상태를 몰라 기본값으로 렌더했다 | 첫 페인트 전 인라인 스크립트 → 594 |
뒤쪽은 렌더를 막아도 안 고쳐진다 — 서버가 낸 HTML 자체가 이미 다른 값이다.
2. 붙였는데 먹었는지 무엇으로 아나
로그도 DOM도 답을 안 준다. <body> 뒤에 붙여도 console·Log·Audits 어디에도 아무것도 안 찍히고, el.blocking.contains('render')는 앞이든 뒤든 true다.1 갈리는 건 첫 페인트 시각 하나다 — 막는 리소스가 끝나기 전에 칠해졌으면 안 먹은 것이다.
3. CDP로 잰다
Page.navigate → Page.loadEventFired를 기다린 뒤, 페이지의 Performance 엔트리를 읽어 둘을 비교한다.
const fcp = performance.getEntriesByName('first-contentful-paint')[0].startTime
const done = performance.getEntriesByType('resource').find((e) => e.name.includes('slow.js')).responseEnd
fcp < done // true 면 막는 리소스가 오기 전에 이미 칠했다 — 안 먹었다
800ms 걸리는 <script async blocking="render" src="/slow.js"> 위치만 바꿔 잰 값이다.1
| 위치 | FCP | slow.js 끝 |
판정 |
|---|---|---|---|
blocking 없음 |
68ms | 830ms | default 가 먼저 칠해짐 |
<head> |
836ms | 816ms | 스크립트 뒤에 첫 페인트 — 먹었다 |
<body> 안 |
16ms | 807ms | default 가 먼저 칠해짐 — 없는 것과 같다 |
4. <body>가 열리기 전에 둔다
컴포넌트 마크업 안이면 이미 늦다. 스펙은 “head 안에 둬라”가 아니라 등록 창을 이렇게 닫는다.
A
Documentdocument allows adding render-blocking elements if document’s content type is “text/html” and the body element of document is null.
<body>가 생기는 순간 등록이 닫히고, 뒤에 붙인 속성은 실패 없이 무시된다. 속성을 모르는 브라우저가 옛 동작으로 떨어지는 것과 같은 모양이라 3처럼 재지 않으면 드러나지 않는다.