728x90
안녕하세요 오늘은 js에서 css에서 적용가능한 변수를 선언하여 이를 이용해 상단 고정 헤드 + 스크롤이 내려가면 반응하여 하얀색 영역이 내려올 수 있도록 해보겠습니다. 사용할 것은 setProperty() 메서드 입니다. 이에 대해 간략히 알아보겠습니다.
사용법은 아래와 같습니다.
<메서드>
setProperty(propertyName, value)
setProperty(propertyName, value, priority)
메서드에 들어가는 파라미터 설명입니다.
<파라미터>
propertyName = 수정할 CSS 속성 이름(하이픈 대소문자)을 나타내는 문자열입니다.
value (옵션) = 새 속성 값을 포함하는 문자열입니다. 지정하지 않으면 빈 문자열로 처리됩니다.
priority (옵션) = CSS 우선 순위를 설정할 수 있는 문자열입니다. 지정하지 않으면 빈 문자열로 처리됩니다. 다음 값이 허용됩니다: 'important', 'undefined', ""(빈값)
아래는 위 개념을 적용한 코드입니다.
stickyheader.html
<header class="header">
<div class="header_inner">
<nav class="nav">
<ul>
<li><a href="#">소개</a></li>
<li><a href="#">연혁</a></li>
<li><a href="#">작품</a></li>
<li><a href="#">문의</a></li>
</ul>
</nav>
</div>
</header>
<section class="hero">
<div class="hero_thumb">
<img src="https://images.unsplash.com/photo-1471958680802-1345a694ba6d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1266&q=80">
</div>
<div class="hero_caption">
<h1>고정 헤드 샘플</h1>
<p>스크롤을 해서 내리면 불투명 하얀색의 배경이 함께 내려와 가시성을 높입니다.</p>
</div>
</section>
<section>
<h1>샘플</h1>
<!--스크롤을 만들기 위해 넣는 긴 문단-->
<p>국회는 헌법 또는 법률에 특별한 규정이 없는 한 재적의원 과반수의 출석과 출석의원 과반수의 찬성으로 의결한다.
가부동수인 때에는 부결된 것으로 본다. 제2항의 재판관중 3인은 국회에서 선출하는 자를, 3인은 대법원장이 지명하는 자를 임명한다.
모든 국민은 거주·이전의 자유를 가진다.
국민의 자유와 권리는 헌법에 열거되지 아니한 이유로 경시되지 아니한다. 재판의 심리와 판결은 공개한다.
다만, 심리는 국가의 안전보장 또는 안녕질서를 방해하거나 선량한 풍속을 해할 염려가 있을 때에는 법원의 결정으로 공개하지 아니할 수 있다.
원장은 국회의 동의를 얻어 대통령이 임명하고, 그 임기는 4년으로 하며, 1차에 한하여 중임할 수 있다.
헌법개정은 국회재적의원 과반수 또는 대통령의 발의로 제안된다.
국가는 주택개발정책등을 통하여 모든 국민이 쾌적한 주거생활을 할 수 있도록 노력하여야 한다.
국가안전보장회의의 조직·직무범위 기타 필요한 사항은 법률로 정한다.
의무교육은 무상으로 한다. 재판의 전심절차로서 행정심판을 할 수 있다.
행정심판의 절차는 법률로 정하되, 사법절차가 준용되어야 한다.
광물 기타 중요한 지하자원·수산자원·수력과 경제상 이용할 수 있는 자연력은 법률이 정하는 바에 의하여 일정한 기간 그 채취·개발 또는 이용을 특허할 수 있다.
국회는 법률에 저촉되지 아니하는 범위안에서 의사와 내부규율에 관한 규칙을 제정할 수 있다.
</p>
</section>
stickyheader.css
/* 박스 모델 */
*, *::before, *::after {
box-sizing: border-box;
}
/* 전체 높이 100vh */
body {
height: 100vh;
}
/* 이미지 스타일 */
img {
display: block;
max-width: 100%;
object-fit: cover;
}
/* 링크 스타일 */
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* 레이아웃 스타일 */
.wrapper {
display: grid;
/* 그리드 컨테이너 중앙 정렬 */
place-content: center;
height: 100vh;
}
/* 헤더 스타일 */
.header {
padding: 2rem;
/*고정 위치, 전체 너비와 높이만큼 자리 차지 */
position: fixed;
inset: 0 0 auto 0;
/*색상 전환 애니메이션*/
transition: color 0.3s;
z-index: 10;
color: #fff;
}
.header::before {
content: "";
/*헤더 크기만큼 영역 설정*/
position: absolute;
inset: 0;
/*헤더 배경 필터 처리*/
background-color: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(5px);
/*높이 0에서 시작해서 아래로 늘어나는 애니메이션*/
transform: scaleY(0);
transition: transform 0.3s;
transform-origin: top center;
will-change: transform;
}
/*스크롤링해서 상단에 고정되면 색상 변경*/
.header.is-sticky {
color: #000;
}
.header.is-sticky::before {
/*높이를 100%로 늘어나게 함 */
transform: scaleY(1);
}
.header_inner {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
}
/* 네비게이션 스타일 */
.nav ul {
list-style: none;
display: flex;
align-items: center;
gap: 1rem;
}
.nav ul li a {
color: inherit;
}
.hero {
display: grid;
position: relative;
/*js에서 설정한 값 가져와서 calc에 파라미터로 적용*/
margin-block-start: calc(var(--_header-h, 4rem) * -1);
min-height: 500px;
}
.hero::before {
content: "";
position: absolute;
inset: 0;
z-index: 0;
background: linear-gradient(180deg, rgba(47, 50, 45, 0) 0%, rgba(47, 50, 45, 0.42) 42.71%, rgba(47, 50, 45, 0.76) 100%);
}
.hero_thumb, .hero_caption {
grid-area: 1/1;
}
.hero_thumb img {
width: 100%;
height: 100%;
object-fit: cover;
}
.hero_caption {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
width: 60%;
margin-inline: auto;
text-align: center;
color: #fff;
}
.hero_caption > p {
font-size: 1.25rem;
text-transform: uppercase;
color: #fae476;
}
.content {
padding-block: 2rem;
width: min(100% - 2rem, 70ch);
margin-inline: auto;
line-height: 1.5;
}
.flow > * + * {
margin-block-start: 1em;
}
stickyheader.js
const header = document.querySelector(".header");
//headerTop 변수에는 header 요소의 위치(top)를 나타내는
//getBoundingClientRect() 메서드를 사용하여 값을 가져오기
const headerTop = header.getBoundingClientRect().top;
//CSS Custom Property(--_header-h)를 생성하고,
//해당 프로퍼티 값으로 header 요소의 높이(offsetHeight`)를 설정.
// >>이후 css에서 값 사용 가능.
document.body.style.setProperty("--_header-h", `${header.offsetHeight}px`);
//마지막으로 window 객체에 scroll 이벤트 리스너를 추가하고,
//스크롤 이벤트가 발생할 때 header 요소가 화면에서 사라지면 .is-sticky 클래스를 추가.
window.addEventListener("scroll", function () {
//스크롤에 따라 .is-sticky 클래스를 추가하고, 보이게 될 때 다시 제거
header.classList.toggle(
"is-sticky",
window.scrollY > headerTop + header.offsetHeight
);
});
위 코드를 완성하면 아래와 같은 모습으로 나타납니다.
자세한 내용은 아래 링크 참고부탁드립니다.
https://developer.mozilla.org/ko/docs/Web/API/Element/getBoundingClientRect
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration/setProperty
'JavaScript' 카테고리의 다른 글
[JavaScript] Canvas로 클릭 이벤트를 받아 애니메이션 만들기(+루프) (0) | 2023.08.22 |
---|---|
[Javascript] localStorage를 활용한 메모 애플리케이션 (0) | 2023.08.13 |
[JavaScript] 스크롤 위치에 따라 메뉴바 변경하기 (0) | 2023.08.10 |
[Javascript] canvas로 애니메이션 만들기 (0) | 2023.08.07 |
[Javascript] 스크롤 이벤트를 활용한 동적 요소 표시 (0) | 2023.08.02 |