Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
## 2026-08-08 - 애니메이션 성능을 위해 top/left 대신 transform 사용
**Learning:** 이 skip-link 전환을 `top`에서 `transform`으로 바꾸면 애니메이션 중 레이아웃 재계산을 피하는 데 유리합니다. 개발자 도구에서 이 전환의 Layout 이벤트가 관찰되지 않았지만, 브라우저·장치별 GPU 가속이나 메인 스레드 비용 0ms를 보장하지는 않습니다.
**Action:** 레이아웃 속성 대신 `transform` 전환을 우선 검토하고, 성능 효과는 브라우저별 측정으로 확인하며 절대적인 GPU·비용 보장으로 기록하지 않습니다.
## 2026-09-19 - Replace querySelector with getElementById and minimize DOM mutations
**Learning:** querySelector can be strictly slower than getElementById since it has to parse the query string and is a more general-purpose search. Furthermore, making unconditional DOM attribute or property updates like `tab.setAttribute("aria-selected", true)` or `panel.hidden = false` in a loop will cause the browser to trigger layout invalidation and thrashing, even if the value hasn't logically changed.
**Action:** When searching by a known ID, prefer the strictly faster `getElementById`. Additionally, when updating DOM attributes or properties in components (e.g. tabs or lists), always check if the current value differs from the target value (e.g. `if (tab.getAttribute("tabindex") !== newTabIndex)`) before applying changes, to prevent redundant DOM mutations and layout thrashing.
19 changes: 16 additions & 3 deletions components/krds-gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,22 @@ document.querySelectorAll(".krds-tabs").forEach((tabs) => {

tabPanels.forEach(({ tab, panel }) => {
const isSelected = tab === nextTab;
tab.setAttribute("aria-selected", String(isSelected));
tab.setAttribute("tabindex", isSelected ? "0" : "-1");
panel.hidden = !isSelected;

// ⚡ Bolt: Avoid redundant DOM mutations to prevent style invalidation and layout thrashing
const newAriaSelected = String(isSelected);
if (tab.getAttribute("aria-selected") !== newAriaSelected) {
tab.setAttribute("aria-selected", newAriaSelected);
}

const newTabIndex = isSelected ? "0" : "-1";
if (tab.getAttribute("tabindex") !== newTabIndex) {
tab.setAttribute("tabindex", newTabIndex);
}

const newHidden = !isSelected;
if (panel.hidden !== newHidden) {
panel.hidden = newHidden;
}
});

if (moveFocus) {
Expand Down
3 changes: 2 additions & 1 deletion i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@ function setLanguage(lang) {
metaDesc = document.querySelector('meta[name="description"]');
ogDesc = document.querySelector('meta[property="og:description"]');
twitterDesc = document.querySelector('meta[name="twitter:description"]');
footerLogo = document.querySelector("#footer-logo");
// ⚡ Bolt: Replace querySelector with strictly faster getElementById
footerLogo = document.getElementById("footer-logo");
}

if (document.documentElement.lang !== lang) {
Expand Down
Loading