라인 주식회사(LINE Corporation)는 커뮤니케이션 앱 라인(LINE)을 기반으로 커뮤니케이션, 콘텐츠, 엔터테인먼트, 광고 사업 등 모바일에 특화된 서비스를 개발 및 운영하고 있습니다. 이외에도, 핀테크와 AI 사업 등 다양한 분야로 진출하고 있습니다. 라인은 자사 미션인 ‘클로징 더 디스턴스(Closing the Distance)’를 바탕으로 전 세계를 대상으로 라인 서비스를 전개하고 있습니다.
▪️ header + main
라인의 슬로건을 메인 화면에 배치하며, 'LINE'이라는 서비스의 색깔을 잘 보여줄 수 있는 영상을 loop로 반복재생함. (동영상은 라인의 홈페이지를 참고하여 직접 편집하여 사용함) 메뉴 네비게이션과 메뉴를 함께 배치하여 사용자가 원하는 서비스를 사용할 수 있도록 배치함
▪️ menu
큰 구성은 회사 / 서비스 / 보도자료 / 채용으로 기존의 라인 메뉴 구성과 유사하게 배치함. 왼쪽에는 회사에 대한 기본 정보 및 언어 전환 (영문 버전은 클릭시 준비중입니다. 라는 알림창), sns로 간결한 배치
▪️ LIFE ON LINE (effect01)
라인의 대표 슬로건인 'LIFE ON LINE'을 메인 화면 다음에 배치하여, 스크롤에 따라 글자가 움직이도록 gsap효과 부여. 기존 라인의 웹페이지와 다르게 효과를 중심으로 it기업의 트렌디한 느낌을 강조하고자 함
▪️ result
라인이라는 기업 및 서비스가 이뤄낸 성과를 강조하여, 지금까지 걸어온 길들을 사용자가 한 눈에 볼 수 있게 구성함. 스크롤에 따라 배치된 방향에서 등장하는 감각적인 효과를 부여함
▪️ service
라인이 대표적으로 제공하는 서비스를 보여줌. 서비스를 보여주는 부분은 되도록 깔끔하고 직관적으로 볼 수 있게 가장 베이직한 구성을 선택함. 이미지와 버튼에 hover을 부여해 너무 단조롭지않게 구성함
▪️ LINER INTERVIEW (effect02)
현재(2022.09 기준) 하반기 신입 공개채용을 가장 큰 이벤트로 하고 있기 때문에, 라인 재직자들의 인터뷰를 구성해 각 직군의 종사자들의 인터뷰를 제공하고자 함. effect01과 같이 스크롤시 글자가 움직이도록 하며, 인터뷰 박스가 스크롤에 맞춰 나오는 효과를 위주로 구성함. 각각 인터뷰 hover시 해당 인터뷰이의 사진이 보여지도록 함.
▪️ news
라인의 최신 동향을 알 수 있는 뉴스 페이지를 가장 하단에 구성하여, 가장 기본적인 swiper형식으로 카드뉴스와 같이 구성함. hover시 padding으로 색상을 부여해 너무 단조롭지 않게 구성.
- index.html : 마크업
- asset
1) css : watch sass -> css
2) font : 사용 폰트
3) image : 사용 이미지
4) js
- main.js
5) scss :- abstracts
- _mixins.scss : 미디어쿼리/말줄임
- base
- _preset.scss : common
- _reset.scss : reset
- _typo.scss : font
- layout
- _footer.scss : footer
- _header.scss : header
- pages
- _index.scss : main
- vender
- _swiper.scss : swiper 링크
- style.scss : @import
clamp()는 최소/최대 값 범위 사이의 값을 표현할 수 있는 경우 사용
선호값은 기본값으로 vw로 작성한다.
ex) fontsize : clamp(35px, 6vw,100px)
🧐 vw로 작성하는 이유?
상대값이기 때문에, px와 같은 절대 단위를 사용하면 clamp함수 기능을 할 수 없다.
최소보다는 작아질 수 없고, max보다는 커질 수 없는 가변값이다.
🧐 vw값을 구하는 방법?
vw계산기를 사용한다.
scss에서 미디어쿼리를 사용할 때, mixin을 사용하여 코드를 정리하면 편하게 사용 가능하다
/*반응형 화면 크기 변수 설정*/
$mobile: 767px; //320
$tablet: 1023px; // 768
$desktop: 1200px; //1024
/*반응형, 브라우저 크기가 767px 이하일때*/
@mixin mobile{
@media (max-width: $mobile){
@content;
}
}
/*반응형, 브라우저 크기가 768이상, 1023px 이하일때*/
@mixin tablet{
@media (max-width: $tablet){
@content;
}
}
/*반응형, 브라우저 크기가 1024px 이상일때*/
@mixin desktop{
@media (max-width: $desktop){
@content;
}
}
🧐 Mixin이란?
‘믹스인’은 재사용 가능한 기능을 만드는 방식을 의미한다.
- 선언하기 :
@mixin
- 사용하기 :
@include
📁abstract
실제 스타일은 없고, 그저 다른 폴더에 정의된 스타일을 돕는 역할
글로벌 변수, 함수는 _variables 파일 / mixins은 _mixins에 작성
📁base
사이트 전반에 걸쳐서 재사용되는 스타일 정의
사이트 전반에 사용될 폰트, 디폴트 스타일 등
📁components
사이트 내에서 재사용가능한 작은 부분들을 정의
layout과 유사하지만, 작은 요소들을 정의한다는 것에서 차이점이 있음
buttons, forms 등 겹치는 요소
📁layout
사이트 구조에 해당하는 레이아웃 정의
headers, footers 등
📁pages
각 페이지에서 사용될 구체적인 스타일
main 페이지 등
🖇️style.scss
폴더에 따라 분류한 scss파일들을 한 군데에 모을 hub 역할
모든 파일을 import해준다.
import만 담당하는 폴더이기 때문에 다른 파일들과 달리 _을 하지 않아야 한다.
상위 선택자의 반복을 피하고 좀 더 편리하게 복잡한 구조를 작성 가능
.sc-main {
width: 100%;
.main-list {
display : flex;
.main-item {
margin : 10px;
}
}
}
&을 사용하여, 부모 선택자를 참조할 수 있음
.btn-nav {
position: absolute;
&.active {
color: #fff;
}
}
이는 btn-nav.active와 같다.
.loading{
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: #06c755;
z-index: 500;
.load-img{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
img{width: 250px;}
}
}
gsap.to('.loading',{ delay:1.2, opacity:0, display:'none', height:0, onComplete:function(){ intro.play() } })
로딩 전체화면에 delay:1.2를 부여해, 1.2초동안 로딩화면 재생
숨겼다가->재생도되록gsap.to('.loading img',{ delay:0.8, opacity:0, onComplete:function(){ intro.play() } })
라인 아이콘은 0.8초동안 재생되도록 보였다가->안보이게
mainTxt = gsap.timeline({}) const intro = gsap.fromTo('.sc-main .title-area .word',{ yPercent:100, opacity:0 },{ yPercent:0, stagger:0.5, opacity:1, paused:true })
로딩화면이 끝난 후, 메인이미지의 텍스트 효과 부여하기
로딩이 끝날 때 까지 멈췄다가, 0->1로 보여지면서 아래에서 위로 올라오는 효과
$('.btn-menu').click(function(e){
e.preventDefault();
if($(this).hasClass('active')){
$('body, .group-menu, .btn-menu').removeClass('active');
$(this).find('.blind').text('메뉴열림');
}else{
$('body, .group-menu, .btn-menu').addClass('active');
$(this).find('.blind').text('메뉴닫힘')
}
});
btn-menu 메뉴를 클릭했을 때,
var FirstScroll = 0;
var prevScrollTop = $(window).scrollTop(),
curr = $(window).scrollTop(); //브라우저 스크롤했을때 위치
$(window).scroll(function(e){
e.preventDefault();
curr = $(this).scrollTop(); //= window scrollTop
//반대스크롤시 보이게
if ( curr < prevScrollTop ){ //반대스크롤하면
$(".group-header").addClass('active'); //메뉴보여짐
$(".group-header").removeClass('hide'); //헤더숨김
if(curr >= 100){ //+curr이 100보다 크거나 같다면
$('.group-header').addClass('active'); //메뉴보이게
}else{
$('.group-header').removeClass('active'); //아니라면 메뉴 안보이게
}
//스크롤시 사라지게
} else if( curr > prevScrollTop ) { //스크롤탑위치에서 스크롤해서 내려가면
$(".group-header").removeClass('active'); //메뉴도 없애면서
$(".group-header").addClass('hide'); //헤더 숨김
}
prevScrollTop = curr;
});
&::before{
content: '';
width: 100px; height: 100px;
position: absolute;
top: 0;right: 0;
background: #06c755;
transform: scale(0);
border-radius: 50%;
transition: 1s;
}
&.active{visibility: visible;
opacity: 1;
&::before{
transform: scale(50);
}
}
group-menu에 before을 만들어, 검은 동그라미 생성
scale을 0으로 한 뒤, active가 되었을 때 함께 transform scale50으로 동그랗게 퍼져가는 모양 생성
group-menu의 텍스트들보다 z-index가 낮아야 함
<li class="result-item" data-x ="-20">
<p class="sort">월간 이용자 수</p>
<div class="img-area">
<em class="num">2억명</em>
<div class="img-box">
<img src="./assets/image/result1.jpg" alt="월간 이용자 수">
</div>
</div>
</li>
<li class="result-item right" data-x ="20">
<p class="sort">다운로드 수</p>
<div class="img-area">
<div class="img-box">
<img src="./assets/image/result2.jpg" alt="다운로드 수">
</div>
<em class="num point">5억회</em>
</div>
</li>
x축 기준으로 오른쪽, 왼쪽에서 li들이 나올 수 있게 구성할 것이기 때문에
data-x를 음수 양수 번갈아서 배치함
데이터 수치를 넣어놔야 컨트롤이 가능함.
const result = document.querySelectorAll('.sc-result .result-item');
result.forEach(el=>{
xVal = (el.dataset.x) ? el.dataset.x : 0;
gsap.from(el,{
scrollTrigger:{
trigger:el,
start:"0% 50%",
end:"top bottom",
scrub:2,
},
xPercent:xVal, //여기에 xval변수값쓰기
opacity:0
})
})
데이터수치에 대한 변수 xVal을 만들어서
if문 작성 : el.dataset.x 값이 있다면(?) el.dataset.x의 값을 사용하고, 없다면(:) 0을 사용하도록 함
gsap에 xPercent에 변수를 넣어, 해당 위치에서 변수값을 사용 할 수 있도록 구성
&.one{left: -100%;}
&.two{right: 0;}
서로 반대방향으로 스크롤될 수 있도록, 시작 지점을 다르게 잡아준다
텍스트를 왼쪽/오른쪽으로 고정해놔서 스크롤해도 공백이 생기지 않게
$('.sc-effect01 .effect-top.one').each(function(i,el){
gsap.to('.sc-effect01 .effect-top.one',{
scrollTrigger:{
trigger:el,
start:'top 95%',
end:'bottom top',
toggleClass: "hide",
scrub:5
},
xPercent:50
})
})
$('.sc-effect01 .effect-top.two').each(function(i,el){
gsap.to('.sc-effect01 .effect-top.two',{
scrollTrigger:{
trigger:el,
start:'top 95%',
end:'bottom top',
toggleClass: "hide",
scrub:5
},
xPercent:-50
})
})
start : 내 스크롤은 맨 위에 닿고, 윈도우기준 거의 바닥(95%)에 닿을 때 시작
.box-area{
left: 100%;
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 1;
width: 100%;
display: flex;
justify-content: center;
}
display flex, justify-content: center으로 가운데정렬하여
최대 스크롤을 해도 맨 왼쪽으로 가지 않도록 고정시킴
const effect02 = gsap.timeline({
scrollTrigger:{
trigger:".sc-effect02",
start:"0% 0%",
end:"+=500%",
scrub: 5,
pin : true,
},
})
effect02.addLabel('eff2')
.to('.sc-effect02 .effect-top.one',{xPercent:50},'eff2')
.to('.sc-effect02 .effect-top.two',{xPercent:-50},'eff2')
.to('.box-area',{ left:'-10%'},'eff2')