👉 사이트명 : 안다르 모바일
👉 작업기간 : 2일 ( 23.07.13. ~ 07.14. )
👉 사용언어 : HTML5, CSS3, Jquery
👉 라이브러리 : Swiper.js
👉 분류 : 모바일 적응형 웹사이트
👉 URL : https://seona-cha.github.io/andar/
✔️ HEADER (스크롤시 효과)
✔️ SVG 사용 - 하나의 파일로 색 변경 효과주기
✔️ GNB 열림 - 바깥영역 클릭시 닫힘
✔️ 비주얼 슬라이더의 height값을 calc()로 계산해서 상하단 여백 보장
✔️ 겹치는 공통 클래스로 컨트롤
✔️ A태그 위에 A태그 띄우기
🔍 전체 태그를 wrapper로 감싸주기 (적응형)
🔍 시멘틱 태그를 활용해 영역 구성
🔍 각각의 section에는 h2태그로 제목 구성
🔍 클래스명에 통일성을 주어 직관적으로 구조를 파악할수있도록 구성
기존 헤더 | 개선 헤더 |
---|---|
안다르 모바일 헤더는 스크롤을 내리면 헤더의 배경색이 변하면서 페이지 최상단에 고정되고, 다시 스크롤이 올라가면 원래 자리로 돌아간다.
기존 안다르 모바일 홈페이지는 1px이라도 스크롤되면 바로 헤더가 상단에 붙는데,
이 부분을 좀더 자연스럽게 만들고 싶어서 나는 헤더의 위치까지 스크롤이 될 경우에 붙도록 만들었다.
$(window).scroll(function(){
curr = $(this).scrollTop(); // 현재 위치 값을 불러옴
target = $('.header').offset().top; // .header의 상단 위치 값을 불러옴
if(curr >= target){
$('.header').addClass('fixed');
$('.header path').css("fill","#000");
}else{
$('.header').removeClass('fixed');
$('.header path').css("fill","#fff");
}
})
위와 같이 스크롤시 색이 변하는 헤더를 만들 때 SVG를 사용하면 효율적이다!
👎 각각 흰색, 검정색의 2가지 파일이 필요
👎 서버에 파일을 두번 요청해야해서 효율적이지 못함
👍 파일 하나로 CSS를 이용해 색상을 다양하게 변경 가능
👍 벡터 방식이라 사이즈를 조정해도 해상도가 깨지지 않음
👀 안다르 모바일 사이트에서는 파일 형식 자체는 SVG를 이용했지만, black 버전과 white 버전을 각각 따로 업로드하여 사용 중인데 ~ 나는 이 부분을 좀더 효율적으로 만들기 위해 하나의 파일만 사용했다. 💁♀️
<h1 class="logo">
<a href="#">
<span class="blind">ANDAR</span>
<svg width='87' height='24' viewBox='0 0 80 21' preserveAspectRatio="none" fill='#fff' xmlns='. . '>
<path fill-rule='evenodd' clip-rule='. . .' fill='#fff'/><!-- Code injected by live-server -->
</svg>
</a>
</h1>
( preserveAspectRatio="none"
는 가로세로 비율을 보존하지 않고 강제로 사이즈를 맞출때 사용)
$(window).scroll(function(){
curr = $(this).scrollTop();
target = $('.header').offset().top;
if(curr >= target){
$('.header').addClass('fixed');
$('.header path').css("fill","#000"); //fill 값 조정
}else{
$('.header').removeClass('fixed');
$('.header path').css("fill","#fff"); //fill 값 조정
}
})
👉 header 영역에 카테고리 메뉴 열고 닫는 부분은 토글 버튼으로 구성했다.
👉 스크린 리더 사용자를 위해 aria-label의 내용도 바뀌도록 만들기 !
slideToggle()
, toggleClass()
메서드로 구성$('.allmenu-toggle.open').click(function(){
$(this).toggleClass('open').toggleClass('close');
$('.allmenu-title').toggleClass('on');
$('.allmenu-area').stop().slideToggle();
.
.
})
$('.allmenu-toggle.open').click(function(){
.
.
if($(this).attr('aria-label') == '메뉴열기'){
$(this).attr('aria-label','메뉴닫기')
}else if($(this).attr('aria-label') == '메뉴닫기'){
$(this).attr('aria-label','메뉴열기')
}
})
// GNB 열고닫기
$('.gnb-btn').click(function(){
$('body').addClass('dimmed');
$('.gnb').addClass('on');
})
$('.gnb-close').click(function(){
$('body').removeClass('dimmed');
$('.gnb').removeClass('on');
})
💡 메뉴/검색영역이 열릴때는 body
에 'dimmed' 클래스를 추가해 아래와 같이 활용했다.
body.dimmed{
height: 100%;
overflow: hidden;
}
body.dimmed:after{
display: block;
position: fixed;
top: 0;left: 0;
width: 100%;
height:100%;
background: rgba(0,0,0,0.65);
z-index:11;
content:'';
opacity: 1;
transition: opacity 0.5s;
}
$(document).click(function(e){
if($('.gnb').hasClass('on')){ //메뉴가 열렸을 때 동작
if(
$('.gnb').has(e.target).length == 0 && // .gnb에 사용자가 클릭한 요소가 포함
$('.gnb-btn').has(e.target).length == 0 // .gnb-btn에 사용자가 클릭한 요소가 포함
){
$('body').removeClass('dimmed');
$('.gnb').removeClass('on');
}
}
})
💣 스크립트를 작성하는 중 조건문에 $('.gnb').has(e.target).length == 0
만 사용했더니,
① GNB 버튼을 누를때부터 .gnb
에 'on'클래스가 생기고,
② GNB버튼이 gnb영역 바깥에 있기때문에 동작하지 않음
👉 그래서 && $('.gnb-btn').has(e.target).length == 0
를 추가해주었다.
height 값이 바뀌어도 상단 배너와 아래 영역 100px 되는 부분을 보장하기 위해 calc()
를 사용했다.
그리고 img태그일 경우 object-fit:cover
를 이용하면, background-size:cover
와 같은 느낌으로 가로세로 비율이 안맞아도 이미지를 강제로 늘리지 않고 맞춰 잘라준다.
.sc-visual img{
width: 100%;
height: calc(100vh - 141px);
object-fit: cover;
}
✔️ 레이아웃이 공통되는 부분은 같은 클래스를 주어 효율적인 CSS 작성
✔️ 차이점이 있는 부분은 다른 클래스로 컨트롤해서 구성해주었다.
<section class="sc-banner membership">
<a href="#">
<h2 class="title">안다르 멤버십</h2>
<p class="desc">5,000원 쿠폰 지급, 상시 5% 할인<br>등급별 혜택을 놓치지마세요.</p>
<span class="banner-more">자세히 보기</span>
</a>
</section>
<section class="sc-banner store">
<a href="#">
<div class="title">안다르 오프라인 스토어 안내</div>
<p class="desc">
전국 백화점과 아울렛에서 안다르 제품을 경험하세요.<br>
안다르만의 스토어 멤버십을 통해<br>
특별한 혜택도 함께 누려보세요.
</p>
<span class="banner-more">자세히 보기</span>
</a>
</section>
👉 각 아이템의 전체 영역은 해당 상품의 링크로 이동
👉 리뷰 부분을 누르면 해당 상품의 리뷰 목록 링크로 이동
이렇게 기획되었다고 가정하고 작업
그런데 마크업 시 a태그 안에 a태그를 사용하는 것은 문법상 맞지 않아서 다른 방법을 택했다.
리뷰 링크는 기존 방식 그대로 작성했다.
<ul class="grid-list prd">
<li class="grid-item">
<a href="#"></a> <!--상품 전체영역 링크-->
<div class="img-box">
<img src="./assets/images/best_2.jpg" alt>
</div>
<div class="product-info">
<span class="review"><a href="#">리뷰 131,739</a></span> <!--리뷰영역은 노멀-->
<strong>[1+1] 에어쿨링 지니 시그니처 레깅스</strong>
<div class="price">
<em class="discount">50%</em>49,000원<del>98,000원</del>
</div>
<span class="label">애슬레저 1위</span>
</div>
</li>
.
.
</ul>
position:absolute
로 위치를 잡아주고, display:block;
처리 후 너비와 높이를 잡아준다.
.prd li > a{
position:absolute;
z-index:1;
width: 100%;
}
.grid-item > a {
height: calc(100% - 50px);
}
.product-info .review{
position: relative;
z-index:2;
.
.
}
👉 탭 메뉴 버튼의 data-tab 속성과 탭 컨텐츠의 id값을 맞춰주었다.
<ul class="tab-list">
<li class="tab-item on"><a href="#" data-tab="#tabcon1">전체</a></li>
<li class="tab-item"><a href="#" data-tab="#tabcon2">우먼즈</a></li>
</ul>
<div class="tabcon on" id="tabcon1">
.
.
</div>
<div class="tabcon" id="tabcon2">
.
.
</div>
/* 메뉴버튼 on시 배경색, 텍스트 색 변경 */
.sc-best .tab-item.on{
background: #b7561f;
font-weight: 600;
color: #fff;
}
/*탭 컨텐츠 display 속성 제어*/
.sc-best .tabcon{
display:none;
}
.sc-best .tabcon.on{
display: block;
}
$('.tab-item').click(function(e){
e.preventDefault(); // a태그 동작으로 페이지가 새로고침되지 않도록
tabCon = $(this).children().data('tab'); // 자식요소인 a의 data-tab을 참조해 변수에 담기
$(this).addClass('on').siblings().removeClass('on'); // 메뉴버튼 CSS 컨트롤을 위함
$(tabCon).addClass('on').siblings().removeClass('on'); // 컨텐츠 display 제어
})
👉 스크롤을 아래로 내릴때 사라지고,
👉 위로 스크롤시 나타나도록 작업
let lastScroll = 0; // 직전 스크롤값을 담을 변수
$(window).scroll(function(){
curr = $(this).scrollTop(); // 현재 스크롤값
if(curr < lastScroll){ //현재 스크롤값이 직전 스크롤값보다 작을경우
$('.quick-menu').addClass('on');
} else {
$('.quick-menu').removeClass('on');
}
lastScroll = curr; //조건문 실행이후 변수에 현재 스크롤값 저장
})
$('.top-btn').click(function(){
window.scrollTo({
top:0,
behavior:"smooth"
})
})