셀 선택

* Ctrl + 클릭: 멀리 떨어진 셀 여러개 선택

* Ctrl + 마우스 드래그 : 인접한 여러 구역을 복수선택

* Shift + F8 : 선택 추가 또는 제거 기능 활설화

* 행번호 클릭 : 해당 행에 속한 모든 열 선택

* 열번호 클릭 : 해당 열에 속한 모든 행 선택

* Shift 누르고 클릭 : 인접한 행 또는 열 지정

* Ctrl 누르고 클릭 : 멀리 떨어진 행 또는 열지정

* Ctrl + A : 전체 셀 선택

* Ctrl + 방향키 : 선택된 데이터와 인접한 데이터의 끝 행이나 끝 열로 이동

* Ctrl + Shift + 방향키 : 선택된 데이터와 인접한 데이터의 끝 행이나 끝 열까지 여러 개의 셀 선택

* Ctrl + A : 만약 데이터가 적힌 셀을 선택했다면, 해당 셀과 인접해있는 모든 데이터 영역에 한해서만 전체 선택됨

 

엑셀 데이터 이동, 복사, 제거

이동

* 데이터가 적힌 셀 클릭 후, 마우스로 드래그하기

* 데이터가 적힌 셀을 Ctrl + X 한 후, 원하는 셀을 선택하여 Ctrl + V 누르기

복사

* 데이터가 적힌 셀 클릭 후, Ctrl 키를 누른 상태에서 마우스로 드래그하기

* 데이터가 적힌 셀을 Ctrl + C를 누른 후, 원하는 셀을 선택하여 Ctrl + V 누르기

제거

*여러 개의 데이터 제거 : Delete 키

*한 개의 데이터 제거 : BackSpace 키

 

여러 개의 셀을 병합, 분할하기

셀 병합

* 병합하여 가운데 맞춤 : 지정된 셀을 하나로 합침,셀 데이터의 가로 방향은 무조건 가운데로

* 셀 병합 : 지정된 셀을 하나로 합침, 셀 데이터는 병합 전 맞춤 방향과 동일함

* 전체 병합 : 동일한 행끼리 셀을 가로로 합침

* 값이 적힌 여러 개의 셀을 병합시 왼쪽 위의 값만 남고 나머지 값은 잃게 됨

셀 분할

* 활성화된 병합 버튼을 클릭

* 이미 병합된 셀을 여러 개의 셀로 분할, 분할된 셀들 중 가장 왼쪽상단의 셀로 데이터가 옮겨짐

 

데이터 "자동 채우기"

자동 채우기 옵션

* 셀 복사 : 기존 데이터와 똑같은 값을 반복시키면서 순서대로 채워놓음

* 연속 데이터 채우기 : 기존 데이터의 규칙에 맞게 연속적으로 더하거나 뺀 데이터를 채워줌(숫자 데이터만 사용 가능)

* 서식만 채우기 : 서식만 그대로 채워지며, 데이터는 변경되지 않음

* 서식 없이 채우기 : 새로운 데이터가 채워지지만, 채워진 영역은 서식이 변경되지 않음

빠른채우기

* [데이터]탭 -> 데이터 도구, 빠른 채우기

연속 데이터 편집

* 숫자가 적힌 셀 하나를 선택, [홈] 탭 -> 편집, '채우기'를 클릭, [계열]

   - 선형 : 단계값에 적은 수만큼 증가 또는 감소, 종료 값을 넘기지 않는 범위까지 연속으로 데이터가 채워짐

   - 급수 : 단계 값에 적은 수만큼 곱해지며, 종료 값을 넘기지 않게 연속으로 데이터가 생성

   - 날짜 : 일, 평일, 월, 년에 따라 채워질 데이터가 달라 각 단위 설정

* 특징

   - 문자 + 숫자 데이터 : 숫자값만 변한 상태로 출력

   - Ctrl 키를 누르고 드래그 : 숫자 값이 적힌 셀 하나를 선택, Ctrl 키를 누른 상태에서 우측하단의 점을 드래그하면 숫자 값이1씩 변화

   - Ctrl 키를 누르지 않고 드래그 : 숫자 값이 적힌 셀 하나를 선택시 지정된 값으로만 똑같이 채워짐, 여러 개 지정 시 연속된 값이 규칙적으로 증가, 감소하며 채워짐

 

셀의 행 높이와 열 너비 변경하기

* 행번호 또는 열번호 선택 후 우클릭, 너비 조정

* 바꾸고 싶은 행 또는 열 선택 후 마우스 드래그

* 셀 크기를 변경할 셀을 마우스로 선택한 뒤, [홈] 탭에 들어간 뒤, 셀 부분에 위치한 '서식'을 선택, 행높이 또는 열너비 조정

* 열너비, 행너비 자동 맞춤 : [홈]탭 -> 셀 -> 서식에서 열 또는 행 너비 자동 맞춤

 

함수를 사용하여 합계 및 평균 구하기

* 합계  :  '='을 입력한 후 sum입력, 괄호 안에 더할 값 삽입

* 평균  :  '='과 average를 차례대로 입력, 열린 괄호에 구하고 싶은 값 삽입

* 자동합계 : 결과값을 출력할 셀을 마우스로 선택, [홈]탭 -> 편집, '자동 합계' 옆에 위치한 화살표 버튼 클릭

    - 중간에 값이 끼어 있을 경우, 중간에 적힌 값까지 계산될 수 있음

 

'$' 기호를 표시하여 절대참조 사용하기

* 위아래 방향으로 자동 채우기 : 행 번호(숫자) 변경, 지정 범위 위아래로 이동

* 좌우 방향으로 자동 채우기: 열 번호(알파벳) 변경, 지정 범위 좌우로 이동

* 절대 참조를 사용해야 하는 경우

    - 할인가 구하기 ex)아메리카노 3000원, 레몬에이드 4200원, 할인 10% 적용시 자동채우기 오류 발생 할인가 = (할인율*(1-원가))

* 상대참조 : 셀 번호가 적힌 연산 식을 다른 셀로 이동시키거나 자동 채우기를 시도할 때 이동한 만큼 지정 범위가 바뀜

* 절대참조 : 셀 번호가 적힌 연산 식을 옮겨도 똑같이 지정 범위가 고정

    - 행 번호만 고정하고 싶다면 숫자로 된 행 번호 왼쪽 옆에만 달러 표시

    - 절대 참조 기호를 빠르게 넣고 싶을 땐 셀을 지정한 상태에서 [F4] 버튼을 클릭

상대참조(B3,C7) 절대참조($B$3,$C$7)
혼합참조($B3,$C7) 혼합참조(B$3,C$7)

 

함수를 사용하여 최대/최솟값 구하기

* 최댓값 '=MAX'를 입력하고 괄호, 숫자 값이 적힌 원하는 범위를 지정

* 최솟값 '=MIN'를 입력하고 괄호, 숫자 값이 적힌 원하는 범위를 지정

 

함수명 공통점 차이점
MIN 사용자가 선택한 여러 개의 셀들 중 가장 작은 값을 찾는 함수 숫자값만 인식 가능
MINA 숫자값, 텍스트, 논리값 모두 인식 가능
MAX 사용자가 선택한 여러개의 셀들 중 가장 큰 값을 찾는 함수 숫자값만 인식 가능
MAXA 숫자값, 텍스트, 논리값 모두 인식 가능

 

셀 참조 스타일 A1 vs R1C1

A1 참조 스타일 R1C1 참조 스타일
열 번호는 알파벳으로, 행 번호는 숫자로 이루어짐 열 번호와 행 번호 모두 숫자로 나타냄
열 -> 행 순서로 셀 주소 표기 행 -> 열 순서로 셀 주소 표기
알파벳 + 숫자 조합 R + 행 번호 + C + 열 번호 조합

 

셀 개수 구하는 엑셀 함수 3가지

함수명 설명
COUNT 사용자가 지정한 셀들 중 숫자가 적힌 셀의 개수를 구함
COUNTA 사용자가 지정한 셀들 중 비어있지 않은 셀 의 개수를 구함
COUNTBLANK 사용자가 지정한 셀들 중 비어있는 셀의 개수를 구함

 


RANK 함수로 순위 매기기

* =RANK(구하고싶은 셀, 범위 지정, 범위지정시 반드시 절대참조($)) + 0을 붙일시 내림차순,1을 붙일시 오름차순

* =RANK.AVG : 동일한 숫자 값이들어있을 때 평균값으로 순위를 구함 (1,1일시 1.5)

* =RANK.EQ  : 동일한 숫자 값이들어있을 때 가장 높은 순위를 구함 (1,1일시 1)

 

엑셀 수식에 문자 포함시키기

* =숫자&"문자"

 

엑셀 기본 표시 형식 모음

* 형식을 바꿀 셀 지정, [홈] 탭을 누른 후,'표시 형식'에 보이는 기능 사용

 

엑셀 줄 바꿈

* [홈] 탭을 누른 다음, '맞춤'에 위치한 '자동 줄 바꿈',셀 넓이 조정

* Alt + Enter을 누를시 수동 줄바꿈

 

엑셀 조건함수 IF 사용 방법

* =IF(조건, 참값, 거짓값)

* 위 함수를 사용시 논리 검사를 수행하여 참 혹은 거짓값 반환

연산자 설명
> 왼쪽 값이 오른쪽보다 클 때
< 오른쪽 값이 왼쪽보다 클 때
>= 왼쪽 값이 오른쪽 값보다 크거나 같을 때
<= 오른쪽 값이 왼쪽 값보다 크거나 같을 때
= 두 값이 서로 같을 때
<> 두 값이 서로 같지 않을 때


AND, OR 함수로 조건 쉽게 걸기

* AND 함수 사용 방법 : IF(AND(조건1,조건2, ...),참, 거짓), 모든 조건이 일치해야 TRUE

* OR 함수 사용 방법 : IF(OR(조건1,조건2, ...),참, 거짓), 조건 하나만 일치해도 TRUE

 

ROUND 함수로 숫자 반올림하기

* 너무 긴 소수는 반드시 반올림 필요, 입력한 자릿수를 기준으로 반올림이 이루어짐

* =ROUND(숫자 값, 자릿수 번호)

* 자릿수 번호가 음수일시 정수 범위 자릿수에서 반올림

 

조건에 맞는 값 SUMIF로 더하기

* =SUMIF(조건을 적용할 셀 범위, 조건, 합계를 구할 셀 범위)

* "*문자*"를 입력시 문자가 들어간 문자를 지정할 수 있음

 

엑셀 필터 사용 방법

* [홈] 탭을 누르고 '정렬 및 필터'를 클릭한 후 필터, Ctrl+Shift+L 단축키

 

엑셀 날짜함수 YEAR, MONTH, DAY

* =YEAR(날짜가 표기된 셀), =MONTH(날짜가 표기된 셀), =DAY(날짜가 표기된 셀), 특정날짜의 '년', '월', '일'에 해당하는 값을 불러옴

* 각 셀에 입력된 숫자 값을 날짜(YYYY-MM-DD)로 나타내려면 DATE를 사용, =DATE(연도,월,일)

 

HOUR함수로 시간 구하기

* =HOUR(시간이 표기된 셀 주소), 시간과 AM/PM사이에 반드시 띄어쓰기

* 시각표시변경을 원할시 해당 셀을 지정, [홈] 메뉴를 클릭, '표시 형식' 옆에 작은 버튼 클릭, 표기형식 고른 뒤 확인

 

몫, 나머지 함수 QUOTIENT, MOD

* =QUOTIENT(a,b) : a를 b로 나눴을 때 몫을 구하는 함수

* =MOD(a,b) : a를 b로 나눴을 때 나머지를 구하는 함수

 

'공부' 카테고리의 다른 글

Firebase 로그인 구현하기 -웹 #1  (0) 2022.05.19
CSS Flex  (0) 2022.04.13

원래하던 곳에서는 버그가 계속걸려서 visual code에서 실행했더니 되었다

https://drive.google.com/file/d/12P4y-UOGsVDBYF5Kf4g8a8ddYi_xsuz3/view?usp=sharing

220124110정성주.pptx
14.92MB

동영상을 이미지로 바꾸어 부드럽게 움직이도록 만들었다

진행사항

1) 웹페이지 골격 잡기
메뉴 스타일링
HTML작성
CSS작성

2) 스크롤 이용한 인터렉션 구현
각 구간의 인터렉션 구현 컨셉잡기
위치가 고정된 요소들 처리하기
스크롤 높이,처리 세팅
활성화 시킬 씬 결정 후 반영 시키기
4개의 구간 각각 스크롤 애니메이션 구현 해주기

3)고해상도 비디오 인터렉션
스크롤로 비디오 제어하기
비디오 인터렉션 적용하기
캔버스 창 사이즈에 맞추기
두가지의 비디오 처리 완료하기

4) 동적 위치와 크기 계산을 이용한 스크롤 인터렉션 구현하기
마지막 구간 인터렉션 구현하기
캔버스 드로우 애니메이션 구현
버그 수정

5) 마무리
aws를 이용한 서버 구축

완성된 코드
https://github.com/tjdwn1340/first-project

GitHub - tjdwn1340/first-project

Contribute to tjdwn1340/first-project development by creating an account on GitHub.

github.com

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

'캡스톤디자인 1' 카테고리의 다른 글

4.인터랙션 구현  (0) 2022.05.18
3.CSS작성  (0) 2022.05.18
2. HTML 작성  (0) 2022.05.18
1.메뉴 스타일링  (0) 2022.05.18
웹페이지 골격 만들기  (0) 2022.04.12

FireBase란?
"백엔드 서비스"

모바일 서버를 개발하기 위해서는 인증, 데이터베이스, 푸시 알람, 스토리지, API 등 모든 것을 개발해야 한다. 그러나 이는 매번 새로운 앱들과 별로 차이가 나지 않기 때문에 복잡한 과정들을 매번 개발할 때마다 하는 것은 시간낭비이다.

FireBase는 이 모든 플렛폼을 프로젝트 구축 시 자동적으로 만들어 준다. 또한 서버를 구축하기 위해서 리눅스 명령어를 알 필요도 없으며 도메인을 구입할 필요가 없고 개발하는 동안에는 서버를 구입할 필요도 없다.

FireBase라는 플랫폼을 통해 프론트엔드 개발자와 백엔드 개발자의 경계가 모호해 질 것이며 적은 비용으로 매우 좋은 앱을 만들 수 있을 것이다.

 

 FireBase의 장점
1. 인증 시스템을 지원한다.

인증은 우리가 알고 있는 로그인 하는 부분을 말한다. 이를 직접 서버로 개발할 경우 매우 복잡한데, 그 이유는 인증된 사용자인지 확인하는 세션처리에서 그 세션으로 데이터베이스와 저장소에 접근해도 문제가 없는지 확인하는 보안처리, 비밀번호 찾기, 아이디 찾기, 비밀번호 변경 등등 복잡한 것들을 구현해야 한다. 그러나 FireBase는 이를 모두 제공하고 있다.
2. NoSQl 기반의 3세대 데이터베이스이다.

NoSQL기반 데이터베이스의 Document DB는, 현재 많이 사용되는 오라클이나 MySQL 같은 관계형 데이터베이스보다 빠르고 간편하다.
또한 FireBase는 다른 데이터 베이스들과 다르게 RTSP(Real Time Stream Protocol) 방식의 데이터베이스를 지원하고 있다. RTSP는 말그대로 실시간으로 데이터들을 전송해주는 방식이다. 이 방식을 사용하면 소켓 기반 서버를 만들어서 통신하는 것 보다 훨씬 코드 양이 줄게되어 코드 몇 줄로도 원하는 구성을 만들 수 있습니다.
3. 원격 구성을 지원한다.

원격구성이란 원격으로 앱의 환경 상태를 구성하는 것을 말한다.
앱의 배경화면 테마나 폰트를 바꾼다던가, 업데이트창과 알림창을 띄우고 앱의 환경을 원격으로 구성할 때 사용하는 기능이다.
4. 콘솔을 제공한다.

콘솔이란 쉽게 말해서 서버 관리자 페이지라고 생각하면 된다.
앱의 서버를 만들게 되면 리눅스, FTP, MySQL(데이터베이스), Node.JS 서버 혹은 Spring 서버, 푸시보내기 API만 구축할 것이 아니라 이 모든 것을 관리할 수 있는 관리자 페이지가 필요하다.
리눅스나 데이터베이스, 서버를 다룰 줄 안다면 관리자 페이지가 필요없을 수도 있지만 그렇지 경우를 위해, 그리고 접근 보안을 위해서 관리자 페이지를 만들어야 한다. 그럼 앱을 만들기 위해서 앱개발자 뿐아니라 서버 개발자까지 필요해지는데, FireBase는 이를 지원해주어 그럴 필요 없어지는 것이다.
5. Analytics를 제공한다.

Analytics는 다수의 사용자가 앱을 어떻게 사용하는지에 대한 통계 정보를 가지고 있다.
추적할 수 있는 정보: 앱의 현재 접속자, 오류통계, 사용자 유지율, 고객들의 앱 업데이트 상태, 사용자들이 특정 페이지에 머문 시간, 이벤트 등
이런 데이터들을 수집하면 사용자가 어떤 페이지에서 흥미를 잃었고, 어떤 페이지가 인기가 많은지 등을 찾아낼 수 있으며 맞춤 마케팅을 할 수 있다.


FireBase의 단점
1. 종종 서버의 응답속도가 느려진다.

Firebase로 채팅 앱을 만들었는데 메시지가 늦게 간다던가, Firebase 인증을 성공하고 나서 메인화면에서 데이터베이스에 접근할 때 서버 응답 시간이 조금 지연되는 경우
그 이유는 서버가 해외에 있기 때문에 종종 처리 속도에 지연이 발생된다고 한다.
Firebase가 국내에서 많이 쓰인다면 구글이 아시아쪽 서버를 구축해 줄것이며 아마 응답 지연이 해결될 것.
2. Firebase의 데이터베이스인 FireStore(신버전)나 RealTimeDatabase(구버전) 모두 쿼리가 매우 빈약하다.

데이터 검색이 어렵다. (SQL에서는 일반적으로 OR 문이나 LIKE 문을 이용해 데이터검색이 가능한데 이들 모두 존재하지 않는다고 한다.)
그래서 Firebase를 사용하는 사용자들은 모든 데이터를 받아와서 안드로이드 기기에서 필터링해주는 방법을 권장하고 있다.

 

<script type="module">
  // Import the functions you need from the SDKs you need
  import { initializeApp } from "https://www.gstatic.com/firebasejs/9.8.1/firebase-app.js";
  // TODO: Add SDKs for Firebase products that you want to use
  // https://firebase.google.com/docs/web/setup#available-libraries

  // Your web app's Firebase configuration
  const firebaseConfig = {
    apiKey: "AIzaSyAQQm4daTxv9OyN7P01OBlZmj-CHoCz9Vc",
    authDomain: "test-web-1-2527f.firebaseapp.com",
    projectId: "test-web-1-2527f",
    storageBucket: "test-web-1-2527f.appspot.com",
    messagingSenderId: "895953517997",
    appId: "1:895953517997:web:c6d73fd3be553f02ce3524"
  };

  // Initialize Firebase
  const app = initializeApp(firebaseConfig);
</script>

'공부' 카테고리의 다른 글

엑셀 기초 요약  (0) 2024.12.16
CSS Flex  (0) 2022.04.13

스크롤 값에 의해 애니매이션 재생

스크롤시 부하가 많이 걸리지 않도록 눈에 보이는 구간만 재생 되도록 구현

 

 

위치가 고정된 요소의 처리

.sticky-elem {
  display: none;
  position: fixed;
  left: 0;
  width: 100%;
}

#show-scene-0 #scroll-section-0 .sticky-elem,
#show-scene-1 #scroll-section-1 .sticky-elem,
#show-scene-2 #scroll-section-2 .sticky-elem,
#show-scene-3 #scroll-section-3 .sticky-elem {
  display: block;
  will-change: transform, opacity;
}

 

자바 스크립트를 넣을 때 마다 무한 로딩이 걸린다

<body class="before-load">를 빼니 실행이 되었다

(() => {
  const scenInfo = [
    {
      //0
      type:'sticky',
      heightNum: 5,//브라우저 높이의 5배로 scrollHeight 세팅
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-0')
      }
    },
      //1
    {
      type:'nomal',
      heightNum: 5,
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-1')
      }
    },
      //2
    {
      type:'sticky',
      heightNum: 5,
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-2')
      }
    },
      //3
    {
      type:'sticky',
      heightNum: 5,
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-3')
      }
    }
  ];

  function setLayout() {
    //각 스크롤 섹션의 높이 세팅
    for (let i = 0; i<sceneInfo.length; i++){
      sceneInfo[i].scrollHeight = sceneInfo[i].heightNum*window.innerHeight;
      sceneInfo[i].objs.container.style.height = '${sceneInfo[i].scrollHeigh}px';
    }

    console.log(sceneInfo);
  }

  window.addEventListener('resize',setLayout);

  setLayout();

})();

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

스크롤 된 값 yOffset이 이전에 있는 scroll heigh 값의 합보다 크면 다음 시작

 

  function scrollLoop(){
    prevScrollHeight = 0;
    for (let i = 0; i < sceneInfo.length; i++){
      prevScrollHeight += sceneInfo[i].scrollHeigh;
    }

    console.log(prevScrollHeight);
  }

prevScrollHeight = 0;를 하여 prevScrollHeight의 값이 누적되지않게 해준다

 

주의-메뉴가 차지하는 영역때문에 영역만큼 미리 바뀐다

 

현재까지 진행된 코드

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>대한민국</title>
    <link
      href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;900&display=swap"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="./default.css" />
    <link rel="stylesheet" href="./main.css" />
  </head>
    <div class="loading">
      <svg class="loading-circle">
        <circle cx="50%" cy="50%" r="25"></circle>
      </svg>
    </div>
    <div class="container">
      <nav class="global-nav">
        <div class="global-nav-links">
          <a href="#" class="global-nav-item">소개</a>
          <a href="#" class="global-nav-item">문화</a>
          <a href="#" class="global-nav-item">여행지</a>
          <a href="#" class="global-nav-item">상품</a>
        </div>
      </nav>
      <nav class="local-nav">
        <div class="local-nav-links">
          <a href="#" class="product-name">대한민국</a>
          <a href="#">개요</a>
          <a href="#">제품사양</a>
          <a href="#">구입하기</a>
        </div>
      </nav>
      <section class="scroll-section" id="scroll-section-0">
        <h1>대한민국</h1>
        <div class="sticky-elem sticky-elem-canvas">
          <canvas id="video-canvas-0" width="1920" height="1080"></canvas>
        </div>
        <div class="sticky-elem main-message a">
          <p>KOREA<br/>대한민국</p>
        </div>
        <div class="sticky-elem main-message b">
          <p>韓国<br />大韩民国</p>
        </div>
        <div class="sticky-elem main-message c">
          <p>República de Corea<br />República da Coreia</p>
        </div>
        <div class="sticky-elem main-message d">
          <p>สาธารณรัฐเกาหลี<br />République de Corée</p>
        </div>
      </section>
      <section class="scroll-section" id="scroll-section-1">
        <p class="description">
          <strong>대한민국</strong>
          영어 명칭은 Republic of Korea. 남쪽으로는 1,000㎞에 이르며, 북쪽으로는 중국·러시아와 접경을 이루고 있다. 남북한 전체 면적은 영국이나 루마니아와 비슷한 크기이고, 남한은 헝가리나 포르투갈보다는 조금 크고 불가리아보다는 조금 작다.
전 국토의 70%가 산악 지역으로 서해로는 완만한 경사를 이루며, 동해로는 급격한 경사를 이룬다. 또한 국토의 면적에 비하여 강이 많은 편이다. 기후는 사계절이 뚜렷하여 덥고 습한 여름과 춥고 건조한 겨울은 길고, 상쾌하고 청명한 날의 봄·가을은 비교적 짧다. 기온은 겨울에는 영하 15℃로 내려가고, 여름에는 34℃로 올라간다.
한국의 전통적인 종교는 샤머니즘·불교·유교이며, 이들은 역대 국가들의 문화발달 및 사상과 행동에 지대한 영향을 끼쳐 왔다. 그 밖에 근대 이후 고유 종교인 천도교를 비롯해 외래 종교인 기독교(개신교)·천주교를 믿는 인구가 급격히 늘어나고 있다. 주민은 한국인이고 인종적으로는 몽골계에 속하며, 고조선시대 이래로 단일민족으로서 존속하여 왔다.
고조선 이후 고대의 삼국시대, 통일신라와 발해시대, 중세의 고려시대, 근세의 조선시대로 이어져 오던 우리나라는 1910년 일제에 의하여 역사상 처음으로 국권을 상실하고 식민지 지배체제하에 놓이게 되었다. 오랫동안 독립투쟁을 벌여오던 우리 민족은 일본이 제2차세계대전에서 패배함으로써 마침내 광복을 맞이하였다.
그러나 광복과 더불어 승전국인 미국과 소련의 군대가 38선을 경계로 남과 북에 각각 진주하여 군정을 실시하게 됨으로써, 일제로부터 광복은 되었으나 독립을 이루지 못한 채 오히려 남북이 분단상태에 놓이게 되었다. 그러나 독립을 이루고자 하는 한국민족의 열망이 국제연합에 반영되어 1947년 제2차 UN총회에서 UN한국감시위원단 감시하의 남북한 동시 총선거가 제의되었으나, 북한은 이를 극력 반대하였다. 그리하여 1948년 5월 10일 남한만의 총선거가 실시되어 5월 31일 제헌국회가 개설되었다.
제헌국회는 7월 17일 「대한민국헌법」을 제정, 공포하고(제9호 개헌 때부터 대한민국 헌법 전문에 ‘대한민국임시정부의 법통을 계승’했다고 명시) 그 달 20일 초대 대통령으로 이승만(李承晩)을 선출하였다. 그리하여 대한민국은 1948년 8월 15일 국내외에 그 성립을 선포하고 자유민주주의국가의 일원으로서 출발하여 오늘에 이르게 되었다. 국제연합은 이와 같이 성립된 대한민국 정부를 ‘한반도에서의 유일한 합법적 정부’로 인정하였다.
대한민국은 정부를 수립하면서 영토를 한반도와 그 부속 도서로 규정, 대한민국의 통치권이 한반도 전체를 통할함을 선포하였다. 그러나 하나의 정치공동체로서의 실제 행정영역은 북위 38°선 이남으로 한정되다가 1953년 휴전 이후에는 휴전선 이남으로 바뀌었다. 휴전선을 경계로 한 현재의 행정영역은 한반도 총면적 22만 258㎢의 약 45%인 9만 9720㎢이다.
대한민국의 수도는 서울특별시이며, 행정적으로는 서울특별시, 1개 특별자치시, 6개 광역시, 1개 특별자치도, 8개 도로 구분되어 있다. 총인구는 1988년에 4197만 5000명이었으나 2015년 현재 5061만 7045명이며, 인구밀도는 1988년에는 423명/㎢이었으나 2010년 현재 485명/㎢이다.
대한민국의 국어는 한국어이며, 문자는 한글 전용을 원칙으로 하되 꼭 필요한 경우에 한하여 한자를 병기하고 있다. 통화는 원화(won貨)이며, 국기는 태극기(太極旗), 국가(國歌)는 애국가, 국화는 무궁화이다.
        </p>
      </section>
      <section class="scroll-section" id="scroll-section-2">
        <div class="sticky-elem sticky-elem-canvas">
          <canvas id="video-canvas-1" width="1920" height="1080"></canvas>
        </div>
        <div class="sticky-elem main-message a">
          <p>
            <small>애국가</small>
            안익태
          </p>
        </div>
        <div class="sticky-elem desc-message b">
          <p>
            동해물과 백두산이 마르고 닳도록
하느님이 보우하사 우리나라 만세
무궁화 삼천리 화려 강산
대한 사람 대한으로 길이 보전하세
          </p>
          <div class="pin"></div>
        </div>
        <div class="sticky-elem desc-message c">
          <p>애국가(愛國歌)는<br /> ‘나라를 사랑하는 노래’라는 뜻</p>
          <div class="pin"></div>
        </div>
      </section>
      <section class="scroll-section" id="scroll-section-3">
        <p class="mid-message">
          <strong>대한민국 인구</strong>
          <br />
          대한민국의 인구는 2022년 기준 대략 5,161만 명으로,
          <br />
          아시아 13위, 세계 28위에 해당
        </p>
        <canvas class="image-blend-canvas" width="1920" height="1080"></canvas>
        <p class="canvas-caption">
          1945년~1948년 분단 당시에는 13도 체제를 유지하고 있었으나, 70여 년의 긴 세월 동안 분단되고 남북의 행정구역의 변동이 있었던 관계로 남북통일 시 광역급 행정구역이 더욱 늘어날 것으로 전망된다. 분단 당시 존재한 13도는 경기도, 강원도, 충청남도, 충청북도, 전라남도, 전라북도, 경상남도, 경상북도, 황해도, 평안남도, 평안북도, 함경남도, 함경북도이다.
          한반도 남쪽 바다(남해, 동중국해)에 있는 제주도는 대한민국에서 가장 큰 섬이다. 울릉도 및 독도와 영종도, 서해 5도, 강화도는 전략상 요충지로 간주된다.
          거제도, 남해도, 진도, 완도, 추자도, 거문도도 있다.
          반도 지형으로, 서쪽은 중국, 북쪽은 북한, 동쪽은 일본에 둘러싸여 있고, 아래쪽은 멀리 대만과, 더 아래쪽으로는 동남아 국가 등이 있다.
        </p>
      </section>
      <footer class="footer">
        220124110, 정성주
      </footer>
    </div>

    <script src="js/main.js"></script>
  </body>
</html>
@charset 'utf-8';

html {
  font-family: "Noto Sans KR", sans-serif;
  font-size: 14px;
}

body {
  overflow-x: hidden;
  color: rgb(29, 29, 31);
  letter-spacing: -0.05em;
  background: white;
}

p {
  line-height: 1.6;
}

a {
  color: rgb(29, 29, 31);
  text-decoration: none;
}

body.before-load {
  overflow: hidden;
}

.container {
  /* 가로 스크롤 방지 */
  overflow-x: hidden;
}

.global-nav {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  width: 100%;
  height: 44px;
  padding: 0 1rem;
}

.local-nav {
  position: absolute;
  top: 45px;
  left: 0;
  z-index: 11;
  width: 100%;
  height: 52px;
  padding: 0 1rem;
  border-bottom: 1px solid #ddd;
}

.local-nav-stick .local-nav {

  position: fixed;
  top: 0;
  background: rgba(255, 255, 255, 0.1);
  -webkit-backdrop-filter: saturate(180%) blur(15px);
  -moz-backdrop-filter: saturate(180%) blur(15px);
  -o-backdrop-filter: saturate(180%) blur(15px);
  backdrop-filter: saturate(180%) blur(15px);
}

.global-nav-links,
.local-nav-links {
  display: flex;
  align-items: center;
  max-width: 1000px;
  height: 100%;
  margin: 0 auto;
}

.global-nav-links {
  justify-content: space-between;
}

.local-nav-links.product-name {
  margin-right: auto;
  font-size: 1.4rem;
  font-weight: bold;
}

.local-nav-links a {
  font-size: 0.8rem;
}

.local-nav-links a:not(.product-name) {
  margin-left: 2em;
}

.scroll-section {
  position: relative;
  padding-top: 50vh;
}

#scroll-section-0 h1 {
  position: relative;
  top: -10vh;
  z-index: 5;
  font-size: 4rem;
  text-align: center;
}

.main-message {
  display: flex;
  align-items: center;
  justify-content: center;
  top: 35vh;
  margin: 5px 0;
  height: 3em;
  font-size: 2.5rem;
  opacity: 0;
}

.main-message p {
  font-weight: bold;
  text-align: center;
  line-height: 1.2;
}

.main-message small {
  display: block;
  margin-bottom: 0.5em;
  font-size: 1.2rem;
}

#scroll-section-2 .main-message {
  font-size: 3.5rem;
}

.description {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 1rem;
  font-size: 1.2rem;
  color: #888;
}

.description strong {
  float: left;
  margin-right: 0.2em;
  font-size: 3rem;
  color: rgb(29, 29, 31);
}

.sticky-elem.desc-message {
	width: 45%;
	font-weight: bold;
	opacity: 0;
}
.pin {
  width: 1px;
  height: 100px;
  background: rgb(29, 29, 31);
}

#scroll-section-2 .b {
  top: 10%;
  left: 40%;
}
#scroll-section-2 .c {
  top: 15%;
  left: 45%;
}

.mid-message {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 1rem;
  font-size: 2rem;
  color: #888;
}

.mid-message strong {
  color: rgb(29, 29, 31);
}

.canvas-caption {
  max-width: 1000px;
  margin: -24rem auto 0;
  padding: 0 1rem;
  font-size: 1.2rem;
  color: #888;
}

.footer {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 7rem;
  color: white;
  background: black;
}
.sticky-elem {
  display: none;
  position: fixed;
  left: 0;
  width: 100%;
}

#show-scene-0 #scroll-section-0 .sticky-elem,
#show-scene-1 #scroll-section-1 .sticky-elem,
#show-scene-2 #scroll-section-2 .sticky-elem,
#show-scene-3 #scroll-section-3 .sticky-elem {
  display: block;
  will-change: transform, opacity;
}
.scroll-effect-end .sticky-elem {
	/* 스크롤 효과가 모두 끝나고, 아래 일반 콘텐츠 영역에서는 sticky-elem들을 모두 안보이도록 */
	display: none !important;
}
.sticky-elem-canvas {
  top: 0;
  height: 100%;
}

.sticky-elem-canvas canvas {
  position: absolute;
  top: 50%;
  left: 50%;
}

#scroll-section-3 {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.image-blend-canvas.sticky {
	position: fixed;
	top: 0;
	z-index: 10;
}

.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  background: white;
  opacity: 0;
  transition: 0.5s;
}

.before-load .container {
  display: none;
}
.before-load .loading {
  opacity: 1;
}

@keyframes loading-spin {
  100% {
    transform: rotate(360deg);
  }
}

@keyframes loading-circle-ani {
  0% {
    stroke-dashoffset: 157;
  }
  75% {
    stroke-dashoffset: -147;
  }
  100% {
    stroke-dashoffset: -157;
  }
}

.loading-circle {
  width: 54px;
  height: 54px;
  animation: loading-spin 3s infinite;
}

.loading-circle circle {
  stroke: black;
  stroke-width: 4;
  stroke-dasharray: 157,157;
  stroke-dashoffset: 0;
  fill: transparent;
	animation: loading-circle-ani 1s infinite;
}

.normal-content {
	margin-bottom: 10rem;
}

@media (min-width: 1024px) {
  #scroll-section-0 h1 {
    font-size: 9vw;
  }
  .main-message {
    font-size: 4vw;
  }
  .description {
    padding: 0;
    font-size: 2rem;
  }
  .description strong {
    font-size: 6rem;
  }
  #scroll-section-2 .main-message {
    font-size: 6vw;
  }
  .main-message small {
    font-size: 1.5vw;
  }
  .sticky-elem.desc-message {
		width: 20%;
  }
  #scroll-section-2 .b {
    top: 20%;
    left: 53%;
  }
  #scroll-section-2 .c {
		left: 55%;
	}
	.mid-message {
		width: 1000px;
		padding: 0;
		font-size: 4vw;
	}
	.canvas-caption {
		margin-top: -8rem;
		padding: 0;
		font-size: 2rem;
  }
}
(() => {

  let yOffset = 0;//window.pageYOffset 대신 쓸 변수
  let prevScrollHeight=0;//현재 스크롤 위치보다 이전에 위치한 스크롤 섹션들의 스크 높이 값의 합
  let currentScene=0;//현재 활성화된 값
  const scenInfo = [
    {
      //0
      type:'sticky',
      heightNum: 5,//브라우저 높이의 5배로 scrollHeight 세팅
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-0')
      }
    },
      //1
    {
      type:'nomal',
      heightNum: 5,
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-1')
      }
    },
      //2
    {
      type:'sticky',
      heightNum: 5,
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-2')
      }
    },
      //3
    {
      type:'sticky',
      heightNum: 5,
      scrollHeight:0,
      objs: {
        container: document.querySelector('#scroll-section-3')
      }
    }
  ];

  function setLayout() {
    //각 스크롤 섹션의 높이 세팅
    for (let i = 0; i<sceneInfo.length; i++){
      sceneInfo[i].scrollHeight = sceneInfo[i].heightNum*window.innerHeight;
      sceneInfo[i].objs.container.style.height = '${sceneInfo[i].scrollHeigh}px';
    }
  }

  function scrollLoop(){
    prevScrollHeight = 0;
    for (let i = 0; i < currentScene; i++){
      prevScrollHeight += sceneInfo[i].scrollHeigh;
    }
    if (yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeigh){
      currentScene++;
    }
    if (yOffset < prevScrollHeight){
      if (currentScene ===0) return;//브라우저 바운스 효과로 인해 마이너스가 되는 것을 방지
      currentScene--;
    }

    document.body.setAttribute('id','show-scene-${currentScene}');

  }

  window.addEventListener('resize',setLayout);
  window.addEventListener('scroll',()=>{
    yOffset=window.pageYOffset;
    scrollLoop();
  });

  setLayout();

})();

document.body.setAttribute('id','show-scene-${currentScene}');

을 하면 각 해당하는 스크롤에 도착했을때 해당하는 문구가 떠야하는데 문구가 뜨지않는다...

 

(() => {

	let yOffset = 0; // window.pageYOffset 대신 쓸 변수
	let prevScrollHeight = 0; // 현재 스크롤 위치(yOffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합
	let currentScene = 0; // 현재 활성화된(눈 앞에 보고있는) 씬(scroll-section)
	let enterNewScene = false; // 새로운 scene이 시작된 순간 true
	let acc = 0.2;
	let delayedYOffset = 0;
	let rafId;
	let rafState;

	const sceneInfo = [
		{
			// 0
			type: 'sticky',
			heightNum: 5, // 브라우저 높이의 5배로 scrollHeight 세팅
			scrollHeight: 0,
			objs: {
				container: document.querySelector('#scroll-section-0'),
				messageA: document.querySelector('#scroll-section-0 .main-message.a'),
				messageB: document.querySelector('#scroll-section-0 .main-message.b'),
				messageC: document.querySelector('#scroll-section-0 .main-message.c'),
				messageD: document.querySelector('#scroll-section-0 .main-message.d'),
				canvas: document.querySelector('#video-canvas-0'),
				context: document.querySelector('#video-canvas-0').getContext('2d'),
				videoImages: []
			},
			values: {
				videoImageCount: 300,
				imageSequence: [0, 299],
				canvas_opacity: [1, 0, { start: 0.9, end: 1 }],
				messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }],
				messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }],
				messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }],
				messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }],
				messageA_translateY_in: [20, 0, { start: 0.1, end: 0.2 }],
				messageB_translateY_in: [20, 0, { start: 0.3, end: 0.4 }],
				messageC_translateY_in: [20, 0, { start: 0.5, end: 0.6 }],
				messageD_translateY_in: [20, 0, { start: 0.7, end: 0.8 }],
				messageA_opacity_out: [1, 0, { start: 0.25, end: 0.3 }],
				messageB_opacity_out: [1, 0, { start: 0.45, end: 0.5 }],
				messageC_opacity_out: [1, 0, { start: 0.65, end: 0.7 }],
				messageD_opacity_out: [1, 0, { start: 0.85, end: 0.9 }],
				messageA_translateY_out: [0, -20, { start: 0.25, end: 0.3 }],
				messageB_translateY_out: [0, -20, { start: 0.45, end: 0.5 }],
				messageC_translateY_out: [0, -20, { start: 0.65, end: 0.7 }],
				messageD_translateY_out: [0, -20, { start: 0.85, end: 0.9 }]
			}
		},
		{
			// 1
			type: 'normal',
			// heightNum: 5, // type normal에서는 필요 없음
			scrollHeight: 0,
			objs: {
				container: document.querySelector('#scroll-section-1'),
				content: document.querySelector('#scroll-section-1 .description')
			}
		},
		{
			// 2
			type: 'sticky',
			heightNum: 5,
			scrollHeight: 0,
			objs: {
				container: document.querySelector('#scroll-section-2'),
				messageA: document.querySelector('#scroll-section-2 .a'),
				messageB: document.querySelector('#scroll-section-2 .b'),
				messageC: document.querySelector('#scroll-section-2 .c'),
				pinB: document.querySelector('#scroll-section-2 .b .pin'),
				pinC: document.querySelector('#scroll-section-2 .c .pin'),
				canvas: document.querySelector('#video-canvas-1'),
				context: document.querySelector('#video-canvas-1').getContext('2d'),
				videoImages: []
			},
			values: {
				videoImageCount: 960,
				imageSequence: [0, 959],
				canvas_opacity_in: [0, 1, { start: 0, end: 0.1 }],
				canvas_opacity_out: [1, 0, { start: 0.95, end: 1 }],
				messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }],
				messageB_translateY_in: [30, 0, { start: 0.5, end: 0.55 }],
				messageC_translateY_in: [30, 0, { start: 0.72, end: 0.77 }],
				messageA_opacity_in: [0, 1, { start: 0.15, end: 0.2 }],
				messageB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }],
				messageC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }],
				messageA_translateY_out: [0, -20, { start: 0.3, end: 0.35 }],
				messageB_translateY_out: [0, -20, { start: 0.58, end: 0.63 }],
				messageC_translateY_out: [0, -20, { start: 0.85, end: 0.9 }],
				messageA_opacity_out: [1, 0, { start: 0.3, end: 0.35 }],
				messageB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }],
				messageC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }],
				pinB_scaleY: [0.5, 1, { start: 0.5, end: 0.55 }],
				pinC_scaleY: [0.5, 1, { start: 0.72, end: 0.77 }],
				pinB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }],
				pinC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }],
				pinB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }],
				pinC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }]
			}
		},
		{
			// 3
			type: 'sticky',
			heightNum: 5,
			scrollHeight: 0,
			objs: {
				container: document.querySelector('#scroll-section-3'),
				canvasCaption: document.querySelector('.canvas-caption'),
				canvas: document.querySelector('.image-blend-canvas'),
				context: document.querySelector('.image-blend-canvas').getContext('2d'),
				imagesPath: [
					'./images/blend-image-1.jpg',
					'./images/blend-image-2.jpg'
				],
				images: []
			},
			values: {
				rect1X: [ 0, 0, { start: 0, end: 0 } ],
				rect2X: [ 0, 0, { start: 0, end: 0 } ],
				blendHeight: [ 0, 0, { start: 0, end: 0 } ],
				canvas_scale: [ 0, 0, { start: 0, end: 0 } ],
				canvasCaption_opacity: [ 0, 1, { start: 0, end: 0 } ],
				canvasCaption_translateY: [ 20, 0, { start: 0, end: 0 } ],
				rectStartY: 0
			}
		}
	];

	function setCanvasImages() {
		let imgElem;
		for (let i = 0; i < sceneInfo[0].values.videoImageCount; i++) {
			imgElem = new Image();
			imgElem.src = `./video/001/IMG_${6726 + i}.JPG`;
			sceneInfo[0].objs.videoImages.push(imgElem);
		}

		let imgElem2;
		for (let i = 0; i < sceneInfo[2].values.videoImageCount; i++) {
			imgElem2 = new Image();
			imgElem2.src = `./video/002/IMG_${7027 + i}.JPG`;
			sceneInfo[2].objs.videoImages.push(imgElem2);
		}

		let imgElem3;
		for (let i = 0; i < sceneInfo[3].objs.imagesPath.length; i++) {
			imgElem3 = new Image();
			imgElem3.src = sceneInfo[3].objs.imagesPath[i];
			sceneInfo[3].objs.images.push(imgElem3);
		}
	}

	function checkMenu() {
		if (yOffset > 44) {
			document.body.classList.add('local-nav-sticky');
		} else {
			document.body.classList.remove('local-nav-sticky');
		}
	}

	function setLayout() {
		// 각 스크롤 섹션의 높이 세팅
		for (let i = 0; i < sceneInfo.length; i++) {
			if (sceneInfo[i].type === 'sticky') {
				sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight;
			} else if (sceneInfo[i].type === 'normal')  {
				sceneInfo[i].scrollHeight = sceneInfo[i].objs.content.offsetHeight + window.innerHeight * 0.5;
			}
            sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px`;
		}

		yOffset = window.pageYOffset;

		let totalScrollHeight = 0;
		for (let i = 0; i < sceneInfo.length; i++) {
			totalScrollHeight += sceneInfo[i].scrollHeight;
			if (totalScrollHeight >= yOffset) {
				currentScene = i;
				break;
			}
		}
		document.body.setAttribute('id', `show-scene-${currentScene}`);

		const heightRatio = window.innerHeight / 1080;
		sceneInfo[0].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`;
		sceneInfo[2].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`;
	}

	function calcValues(values, currentYOffset) {
		let rv;
		// 현재 씬(스크롤섹션)에서 스크롤된 범위를 비율로 구하기
		const scrollHeight = sceneInfo[currentScene].scrollHeight;
		const scrollRatio = currentYOffset / scrollHeight;

		if (values.length === 3) {
			// start ~ end 사이에 애니메이션 실행
			const partScrollStart = values[2].start * scrollHeight;
			const partScrollEnd = values[2].end * scrollHeight;
			const partScrollHeight = partScrollEnd - partScrollStart;

			if (currentYOffset >= partScrollStart && currentYOffset <= partScrollEnd) {
				rv = (currentYOffset - partScrollStart) / partScrollHeight * (values[1] - values[0]) + values[0];
			} else if (currentYOffset < partScrollStart) {
				rv = values[0];
			} else if (currentYOffset > partScrollEnd) {
				rv = values[1];
			}
		} else {
			rv = scrollRatio * (values[1] - values[0]) + values[0];
		}

		return rv;
	}

	function playAnimation() {
		const objs = sceneInfo[currentScene].objs;
		const values = sceneInfo[currentScene].values;
		const currentYOffset = yOffset - prevScrollHeight;
		const scrollHeight = sceneInfo[currentScene].scrollHeight;
		const scrollRatio = currentYOffset / scrollHeight;

		switch (currentScene) {
			case 0:
				// console.log('0 play');
				// let sequence = Math.round(calcValues(values.imageSequence, currentYOffset));
				// objs.context.drawImage(objs.videoImages[sequence], 0, 0);
				objs.canvas.style.opacity = calcValues(values.canvas_opacity, currentYOffset);

				if (scrollRatio <= 0.22) {
					// in
					objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset);
					objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`;
				} else {
					// out
					objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
					objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`;
				}

				if (scrollRatio <= 0.42) {
					// in
					objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset);
					objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
				} else {
					// out
					objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
					objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`;
				}

				if (scrollRatio <= 0.62) {
					// in
					objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset);
					objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
				} else {
					// out
					objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
					objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`;
				}

				if (scrollRatio <= 0.82) {
					// in
					objs.messageD.style.opacity = calcValues(values.messageD_opacity_in, currentYOffset);
					objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_in, currentYOffset)}%, 0)`;
				} else {
					// out
					objs.messageD.style.opacity = calcValues(values.messageD_opacity_out, currentYOffset);
					objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_out, currentYOffset)}%, 0)`;
				}

				break;

			case 2:
				// console.log('2 play');
				// let sequence2 = Math.round(calcValues(values.imageSequence, currentYOffset));
				// objs.context.drawImage(objs.videoImages[sequence2], 0, 0);

				if (scrollRatio <= 0.5) {
					// in
					objs.canvas.style.opacity = calcValues(values.canvas_opacity_in, currentYOffset);
				} else {
					// out
					objs.canvas.style.opacity = calcValues(values.canvas_opacity_out, currentYOffset);
				}

				if (scrollRatio <= 0.25) {
					// in
					objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset);
					objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`;
				} else {
					// out
					objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
					objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`;
				}

				if (scrollRatio <= 0.57) {
					// in
					objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
					objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset);
					objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
				} else {
					// out
					objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`;
					objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
					objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
				}

				if (scrollRatio <= 0.83) {
					// in
					objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
					objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset);
					objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
				} else {
					// out
					objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`;
					objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
					objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
				}

				// currentScene 3에서 쓰는 캔버스를 미리 그려주기 시작
				if (scrollRatio > 0.9) {
					const objs = sceneInfo[3].objs;
					const values = sceneInfo[3].values;
					const widthRatio = window.innerWidth / objs.canvas.width;
					const heightRatio = window.innerHeight / objs.canvas.height;
					let canvasScaleRatio;

					if (widthRatio <= heightRatio) {
						// 캔버스보다 브라우저 창이 홀쭉한 경우
						canvasScaleRatio = heightRatio;
					} else {
						// 캔버스보다 브라우저 창이 납작한 경우
						canvasScaleRatio = widthRatio;
					}

					objs.canvas.style.transform = `scale(${canvasScaleRatio})`;
					objs.context.fillStyle = 'white';
					objs.context.drawImage(objs.images[0], 0, 0);

					// 캔버스 사이즈에 맞춰 가정한 innerWidth와 innerHeight
					const recalculatedInnerWidth = document.body.offsetWidth / canvasScaleRatio;
					const recalculatedInnerHeight = window.innerHeight / canvasScaleRatio;

					const whiteRectWidth = recalculatedInnerWidth * 0.15;
					values.rect1X[0] = (objs.canvas.width - recalculatedInnerWidth) / 2;
					values.rect1X[1] = values.rect1X[0] - whiteRectWidth;
					values.rect2X[0] = values.rect1X[0] + recalculatedInnerWidth - whiteRectWidth;
					values.rect2X[1] = values.rect2X[0] + whiteRectWidth;

					// 좌우 흰색 박스 그리기
					objs.context.fillRect(
						parseInt(values.rect1X[0]),
						0,
						parseInt(whiteRectWidth),
						objs.canvas.height
					);
					objs.context.fillRect(
						parseInt(values.rect2X[0]),
						0,
						parseInt(whiteRectWidth),
						objs.canvas.height
					);
				}

				break;

			case 3:
				// console.log('3 play');
				let step = 0;
				// 가로/세로 모두 꽉 차게 하기 위해 여기서 세팅(계산 필요)
				const widthRatio = window.innerWidth / objs.canvas.width;
				const heightRatio = window.innerHeight / objs.canvas.height;
				let canvasScaleRatio;

				if (widthRatio <= heightRatio) {
					// 캔버스보다 브라우저 창이 홀쭉한 경우
					canvasScaleRatio = heightRatio;
				} else {
					// 캔버스보다 브라우저 창이 납작한 경우
					canvasScaleRatio = widthRatio;
				}

				objs.canvas.style.transform = `scale(${canvasScaleRatio})`;
				objs.context.fillStyle = 'white';
				objs.context.drawImage(objs.images[0], 0, 0);

				// 캔버스 사이즈에 맞춰 가정한 innerWidth와 innerHeight
				const recalculatedInnerWidth = document.body.offsetWidth / canvasScaleRatio;
				const recalculatedInnerHeight = window.innerHeight / canvasScaleRatio;

				if (!values.rectStartY) {
					// values.rectStartY = objs.canvas.getBoundingClientRect().top;
					values.rectStartY = objs.canvas.offsetTop + (objs.canvas.height - objs.canvas.height * canvasScaleRatio) / 2;
					values.rect1X[2].start = (window.innerHeight / 2) / scrollHeight;
					values.rect2X[2].start = (window.innerHeight / 2) / scrollHeight;
					values.rect1X[2].end = values.rectStartY / scrollHeight;
					values.rect2X[2].end = values.rectStartY / scrollHeight;
				}

				const whiteRectWidth = recalculatedInnerWidth * 0.15;
				values.rect1X[0] = (objs.canvas.width - recalculatedInnerWidth) / 2;
				values.rect1X[1] = values.rect1X[0] - whiteRectWidth;
				values.rect2X[0] = values.rect1X[0] + recalculatedInnerWidth - whiteRectWidth;
				values.rect2X[1] = values.rect2X[0] + whiteRectWidth;

				// 좌우 흰색 박스 그리기
				objs.context.fillRect(
					parseInt(calcValues(values.rect1X, currentYOffset)),
					0,
					parseInt(whiteRectWidth),
					objs.canvas.height
				);
				objs.context.fillRect(
					parseInt(calcValues(values.rect2X, currentYOffset)),
					0,
					parseInt(whiteRectWidth),
					objs.canvas.height
				);

				if (scrollRatio < values.rect1X[2].end) {
					step = 1;
					// console.log('캔버스 닿기 전');
					objs.canvas.classList.remove('sticky');
				} else {
					step = 2;
					// console.log('캔버스 닿은 후');
					// 이미지 블렌드
					// values.blendHeight: [ 0, 0, { start: 0, end: 0 } ]
					values.blendHeight[0] = 0;
					values.blendHeight[1] = objs.canvas.height;
					values.blendHeight[2].start = values.rect1X[2].end;
					values.blendHeight[2].end = values.blendHeight[2].start + 0.2;
					const blendHeight = calcValues(values.blendHeight, currentYOffset);

					objs.context.drawImage(objs.images[1],
						0, objs.canvas.height - blendHeight, objs.canvas.width, blendHeight,
						0, objs.canvas.height - blendHeight, objs.canvas.width, blendHeight
					);

					objs.canvas.classList.add('sticky');
					objs.canvas.style.top = `${-(objs.canvas.height - objs.canvas.height * canvasScaleRatio) / 2}px`;

					if (scrollRatio > values.blendHeight[2].end) {
						values.canvas_scale[0] = canvasScaleRatio;
						values.canvas_scale[1] = document.body.offsetWidth / (1.5 * objs.canvas.width);
						values.canvas_scale[2].start = values.blendHeight[2].end;
						values.canvas_scale[2].end = values.canvas_scale[2].start + 0.2;

						objs.canvas.style.transform = `scale(${calcValues(values.canvas_scale, currentYOffset)})`;
						objs.canvas.style.marginTop = 0;
					}

					if (scrollRatio > values.canvas_scale[2].end
						&& values.canvas_scale[2].end > 0) {
						objs.canvas.classList.remove('sticky');
						objs.canvas.style.marginTop = `${scrollHeight * 0.4}px`;

						values.canvasCaption_opacity[2].start = values.canvas_scale[2].end;
						values.canvasCaption_opacity[2].end = values.canvasCaption_opacity[2].start + 0.1;
						values.canvasCaption_translateY[2].start = values.canvasCaption_opacity[2].start;
						values.canvasCaption_translateY[2].end = values.canvasCaption_opacity[2].end;
						objs.canvasCaption.style.opacity = calcValues(values.canvasCaption_opacity, currentYOffset);
						objs.canvasCaption.style.transform = `translate3d(0, ${calcValues(values.canvasCaption_translateY, currentYOffset)}%, 0)`;
					} else {
						objs.canvasCaption.style.opacity = values.canvasCaption_opacity[0];
					}
				}

				break;
		}
	}

	function scrollLoop() {
		enterNewScene = false;
		prevScrollHeight = 0;

		for (let i = 0; i < currentScene; i++) {
			prevScrollHeight += sceneInfo[i].scrollHeight;
		}

		if (delayedYOffset < prevScrollHeight + sceneInfo[currentScene].scrollHeight) {
			document.body.classList.remove('scroll-effect-end');
		}

		if (delayedYOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) {
			enterNewScene = true;
			if (currentScene === sceneInfo.length - 1) {
				document.body.classList.add('scroll-effect-end');
			}
			if (currentScene < sceneInfo.length - 1) {
				currentScene++;
			}
			document.body.setAttribute('id', `show-scene-${currentScene}`);
		}

		if (delayedYOffset < prevScrollHeight) {
			enterNewScene = true;
			// 브라우저 바운스 효과로 인해 마이너스가 되는 것을 방지(모바일)
			if (currentScene === 0) return;
			currentScene--;
			document.body.setAttribute('id', `show-scene-${currentScene}`);
		}

		if (enterNewScene) return;

		playAnimation();
	}

	function loop() {
		delayedYOffset = delayedYOffset + (yOffset - delayedYOffset) * acc;

		if (!enterNewScene) {
			if (currentScene === 0 || currentScene === 2) {
				const currentYOffset = delayedYOffset - prevScrollHeight;
				const objs = sceneInfo[currentScene].objs;
				const values = sceneInfo[currentScene].values;
				let sequence = Math.round(calcValues(values.imageSequence, currentYOffset));
				if (objs.videoImages[sequence]) {
					objs.context.drawImage(objs.videoImages[sequence], 0, 0);
				}
			}
		}

        // 일부 기기에서 페이지 끝으로 고속 이동하면 body id가 제대로 인식 안되는 경우를 해결
        // 페이지 맨 위로 갈 경우: scrollLoop와 첫 scene의 기본 캔버스 그리기 수행
        if (delayedYOffset < 1) {
            scrollLoop();
            sceneInfo[0].objs.canvas.style.opacity = 1;
            sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0], 0, 0);
        }
        // 페이지 맨 아래로 갈 경우: 마지막 섹션은 스크롤 계산으로 위치 및 크기를 결정해야할 요소들이 많아서 1픽셀을 움직여주는 것으로 해결
        if ((document.body.offsetHeight - window.innerHeight) - delayedYOffset < 1) {
            let tempYOffset = yOffset;
            scrollTo(0, tempYOffset - 1);
        }

		rafId = requestAnimationFrame(loop);

		if (Math.abs(yOffset - delayedYOffset) < 1) {
			cancelAnimationFrame(rafId);
			rafState = false;
		}
	}

	window.addEventListener('load', () => {
		setLayout(); // 중간에 새로고침 시, 콘텐츠 양에 따라 높이 계산에 오차가 발생하는 경우를 방지하기 위해 before-load 클래스 제거 전에도 확실하게 높이를 세팅하도록 한번 더 실행
        document.body.classList.remove('before-load');
        setLayout();
        sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0], 0, 0);

		// 중간에서 새로고침 했을 경우 자동 스크롤로 제대로 그려주기
        let tempYOffset = yOffset;
        let tempScrollCount = 0;
        if (tempYOffset > 0) {
            let siId = setInterval(() => {
                scrollTo(0, tempYOffset);
                tempYOffset += 5;

                if (tempScrollCount > 20) {
                    clearInterval(siId);
                }
                tempScrollCount++;
            }, 20);
        }

        window.addEventListener('scroll', () => {
            yOffset = window.pageYOffset;
            scrollLoop();
  			checkMenu();

  			if (!rafState) {
  				rafId = requestAnimationFrame(loop);
  				rafState = true;
  			}
  		});

  		window.addEventListener('resize', () => {
  			if (window.innerWidth > 900) {
				window.location.reload();
			}
  		});

  		window.addEventListener('orientationchange', () => {
			scrollTo(0, 0);
			setTimeout(() => {
				window.location.reload();
			}, 500);
  		});

  		document.querySelector('.loading').addEventListener('transitionend', (e) => {
  			document.body.removeChild(e.currentTarget);
  		});

	});

	setCanvasImages();

})();

'캡스톤디자인 1' 카테고리의 다른 글

first project 완성본  (0) 2022.06.11
3.CSS작성  (0) 2022.05.18
2. HTML 작성  (0) 2022.05.18
1.메뉴 스타일링  (0) 2022.05.18
웹페이지 골격 만들기  (0) 2022.04.12

.scroll-section {
  position: relative;
  padding-top: 50vh;
}

브라우저 창의 절반만큼 padding-top주기

 

.main-message {
  display: flex;
  align-items: center;
  justify-content: center;
  top: 35vh;
  margin: 5px 0;
  height: 3em;
  font-size: 2.5rem;
  opacity: 0;
}

한줄이든 두줄이든 박스의 가운데 정렬이 되도록 하기위해 구현

박스의 크기가 구현이 되어 있으면 박스안에서 센터에 정열된다(컨트롤을 쉽게 하기위해)

 

웹을 줄이면 함께 작아진다

모바일, pc버전 코드 작성

 

 

vw는 창크기의 퍼센트

rem은 고정값 html의 폰트사이즈의 퍼센트

 

@charset 'utf-8';

html {
  font-family: "Noto Sans KR", sans-serif;
  font-size: 14px;
}

body {
  overflow-x: hidden;
  color: rgb(29, 29, 31);
  letter-spacing: -0.05em;
  background: white;
}

p {
  line-height: 1.6;
}

a {
  color: rgb(29, 29, 31);
  text-decoration: none;
}

body.before-load {
  overflow: hidden;
}

.container {
  /* 가로 스크롤 방지 */
  overflow-x: hidden;
}

.global-nav {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  width: 100%;
  height: 44px;
  padding: 0 1rem;
}

.local-nav {
  position: absolute;
  top: 45px;
  left: 0;
  z-index: 11;
  width: 100%;
  height: 52px;
  padding: 0 1rem;
  border-bottom: 1px solid #ddd;
}

.local-nav-stick .local-nav {

  position: fixed;
  top: 0;
  background: rgba(255, 255, 255, 0.1);
  -webkit-backdrop-filter: saturate(180%) blur(15px);
  -moz-backdrop-filter: saturate(180%) blur(15px);
  -o-backdrop-filter: saturate(180%) blur(15px);
  backdrop-filter: saturate(180%) blur(15px);
}

.global-nav-links,
.local-nav-links {
  display: flex;
  align-items: center;
  max-width: 1000px;
  height: 100%;
  margin: 0 auto;
}

.global-nav-links {
  justify-content: space-between;
}

.local-nav-links .product-name {
  margin-right: auto;
  font-size: 1.4rem;
  font-weight: bold;
}

.local-nav-links a {
  font-size: 0.8rem;
}

.local-nav-links a:not(.product-name) {
  margin-left: 2em;
}

.scroll-section {
  position: relative;
  padding-top: 50vh;
}

#scroll-section-0 h1 {
  position: relative;
  top: -10vh;
  z-index: 5;
  font-size: 4rem;
  text-align: center;
}

.main-message {
  display: flex;
  align-items: center;
  justify-content: center;
  top: 35vh;
  margin: 5px 0;
  height: 3em;
  font-size: 2.5rem;
  opacity: 0;
}

.main-message p {
  font-weight: bold;
  text-align: center;
  line-height: 1.2;
}

.main-message small {
  display: block;
  margin-bottom: 0.5em;
  font-size: 1.2rem;
}

#scroll-section-2 .main-message {
  font-size: 3.5rem;
}

.description {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 1rem;
  font-size: 1.2rem;
  color: #888;
}

.description strong {
  float: left;
  margin-right: 0.2em;
  font-size: 3rem;
  color: rgb(29, 29, 31);
}

.desc-message {
  width: 50%;
  font-weight: bold;
  opacity: 0;
}
.pin {
  width: 1px;
  height: 100px;
  background: rgb(29, 29, 31);
}

#scroll-section-2 .b {
  top: 10%;
  left: 40%;
}
#scroll-section-2 .c {
  top: 15%;
  left: 45%;
}

.mid-message {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 1rem;
  font-size: 2rem;
  color: #888;
}

.mid-message strong {
  color: rgb(29, 29, 31);
}

.canvas-caption {
  max-width: 1000px;
  margin: -30rem auto 0;
  text-align: center;
  padding: 0 1rem;
  font-size: 1.2rem;
  color: #888;
}

.footer {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 7rem;
  color: white;
  background: black;
}
.sticky-elem {
  display: none;
  position: fixed;
  left: 0;
  width: 100%;
}

#show-scene-0 #scroll-section-0 .sticky-elem,
#show-scene-1 #scroll-section-1 .sticky-elem,
#show-scene-2 #scroll-section-2 .sticky-elem,
#show-scene-3 #scroll-section-3 .sticky-elem {
  display: block;
  will-change: transform, opacity;
}

.sticky-elem-canvas {
  top: 0;
  height: 100%;
}

.sticky-elem-canvas canvas {
  position: absolute;
  top: 50%;
  left: 50%;
}

#scroll-section-3 {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.image-blend-canvas.sticky {
  position: fixed;
  top: 0;
}

.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  background: white;
  opacity: 0;
  transition: 0.5s;
}

.before-load .container {
  display: none;
}
.before-load .loading {
  opacity: 1;
}

@keyframes loading-spin {
  100% {
    transform: rotate(360deg);
  }
}

@keyframes loading-circle-ani {
  0% {
    stroke-dashoffset: 157;
  }
  75% {
    stroke-dashoffset: -147;
  }
  100% {
    stroke-dashoffset: -157;
  }
}

.loading-circle {
  width: 54px;
  height: 54px;
  animation: loading-spin 3s infinite;
}

.loading-circle circle {
  stroke: black;
  stroke-width: 4;
  stroke-dasharray: 157;
  stroke-dashoffset: 0;
  fill: none;
  animation: loading-circle-ani 1s infinite;
}


@media (min-width: 1024px) {
  #scroll-section-0 h1 {
    font-size: 9vw;
  }
  .main-message {
    font-size: 4vw;
  }
  .description {
    padding: 0;
    font-size: 2rem;
  }
  .description strong {
    font-size: 6rem;
  }
  #scroll-section-2 .main-message {
    font-size: 6vw;
  }
  .main-message small {
    font-size: 1.5vw;
  }
  .desc-message {
    width: 20%;
  }
  #scroll-section-2 .b {
    top: 20%;
    left: 53%;
  }
  #scroll-section-2 .c {
    left: 55%;
  }
  .mid-message {
    width: 1000px;
    padding: 0;
    font-size: 4vw;
  }
  .canvas-caption {
    margin-top: -8rem;
    padding: 0;
    font-size: 2rem;
  }

  .scroll-section {
    padding-top: 50vh;
  }
}

'캡스톤디자인 1' 카테고리의 다른 글

first project 완성본  (0) 2022.06.11
4.인터랙션 구현  (0) 2022.05.18
2. HTML 작성  (0) 2022.05.18
1.메뉴 스타일링  (0) 2022.05.18
웹페이지 골격 만들기  (0) 2022.04.12

<section class="scroll-section">

스크롤 구간을 나눈다

<section class="scroll-section" id="scroll-section-0">

<section class="scroll-section" id="scroll-section-1">

<section class="scroll-section" id="scroll-section-2">

<section class="scroll-section" id="scroll-section-3">

각각의 고유 아이디 설정

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>대한민국</title>
    <link
      href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;900&display=swap"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="./default.css" />
    <link rel="stylesheet" href="./main.css" />
  </head>
  <body class="before-load">
    <div class="loading">
      <svg class="loading-circle">
        <circle cx="50%" cy="50%" r="25"></circle>
      </svg>
    </div>
    <div class="container">
      <nav class="global-nav">
        <div class="global-nav-links">
          <a href="#" class="global-nav-item">소개</a>
          <a href="#" class="global-nav-item">문화</a>
          <a href="#" class="global-nav-item">여행지</a>
          <a href="#" class="global-nav-item">상품</a>
        </div>
      </nav>
      <nav class="local-nav">
        <div class="local-nav-links">
          <a href="#" class="product-name">대한민국</a>
          <a href="#">개요</a>
          <a href="#">제품사양</a>
          <a href="#">구입하기</a>
        </div>
      </nav>
      <section class="scroll-section" id="scroll-section-0">
        <h1>대한민국</h1>
        <div class="sticky-elem sticky-elem-canvas">
          <canvas id="video-canvas-0" width="1920" height="1080"></canvas>
        </div>
        <div class="sticky-elem main-message a">
          <p>KOREA<br/>대한민국</p>
        </div>
        <div class="sticky-elem main-message b">
          <p>韓国<br />大韩民国</p>
        </div>
        <div class="sticky-elem main-message c">
          <p>República de Corea<br />República da Coreia</p>
        </div>
        <div class="sticky-elem main-message d">
          <p>สาธารณรัฐเกาหลี<br />République de Corée</p>
        </div>
      </section>
      <section class="scroll-section" id="scroll-section-1">
        <p class="description">
          <strong>대한민국</strong>
          영어 명칭은 Republic of Korea. 남쪽으로는 1,000㎞에 이르며, 북쪽으로는 중국·러시아와 접경을 이루고 있다. 남북한 전체 면적은 영국이나 루마니아와 비슷한 크기이고, 남한은 헝가리나 포르투갈보다는 조금 크고 불가리아보다는 조금 작다.
전 국토의 70%가 산악 지역으로 서해로는 완만한 경사를 이루며, 동해로는 급격한 경사를 이룬다. 또한 국토의 면적에 비하여 강이 많은 편이다. 기후는 사계절이 뚜렷하여 덥고 습한 여름과 춥고 건조한 겨울은 길고, 상쾌하고 청명한 날의 봄·가을은 비교적 짧다. 기온은 겨울에는 영하 15℃로 내려가고, 여름에는 34℃로 올라간다.
한국의 전통적인 종교는 샤머니즘·불교·유교이며, 이들은 역대 국가들의 문화발달 및 사상과 행동에 지대한 영향을 끼쳐 왔다. 그 밖에 근대 이후 고유 종교인 천도교를 비롯해 외래 종교인 기독교(개신교)·천주교를 믿는 인구가 급격히 늘어나고 있다. 주민은 한국인이고 인종적으로는 몽골계에 속하며, 고조선시대 이래로 단일민족으로서 존속하여 왔다.
고조선 이후 고대의 삼국시대, 통일신라와 발해시대, 중세의 고려시대, 근세의 조선시대로 이어져 오던 우리나라는 1910년 일제에 의하여 역사상 처음으로 국권을 상실하고 식민지 지배체제하에 놓이게 되었다. 오랫동안 독립투쟁을 벌여오던 우리 민족은 일본이 제2차세계대전에서 패배함으로써 마침내 광복을 맞이하였다.
그러나 광복과 더불어 승전국인 미국과 소련의 군대가 38선을 경계로 남과 북에 각각 진주하여 군정을 실시하게 됨으로써, 일제로부터 광복은 되었으나 독립을 이루지 못한 채 오히려 남북이 분단상태에 놓이게 되었다. 그러나 독립을 이루고자 하는 한국민족의 열망이 국제연합에 반영되어 1947년 제2차 UN총회에서 UN한국감시위원단 감시하의 남북한 동시 총선거가 제의되었으나, 북한은 이를 극력 반대하였다. 그리하여 1948년 5월 10일 남한만의 총선거가 실시되어 5월 31일 제헌국회가 개설되었다.
제헌국회는 7월 17일 「대한민국헌법」을 제정, 공포하고(제9호 개헌 때부터 대한민국 헌법 전문에 ‘대한민국임시정부의 법통을 계승’했다고 명시) 그 달 20일 초대 대통령으로 이승만(李承晩)을 선출하였다. 그리하여 대한민국은 1948년 8월 15일 국내외에 그 성립을 선포하고 자유민주주의국가의 일원으로서 출발하여 오늘에 이르게 되었다. 국제연합은 이와 같이 성립된 대한민국 정부를 ‘한반도에서의 유일한 합법적 정부’로 인정하였다.
대한민국은 정부를 수립하면서 영토를 한반도와 그 부속 도서로 규정, 대한민국의 통치권이 한반도 전체를 통할함을 선포하였다. 그러나 하나의 정치공동체로서의 실제 행정영역은 북위 38°선 이남으로 한정되다가 1953년 휴전 이후에는 휴전선 이남으로 바뀌었다. 휴전선을 경계로 한 현재의 행정영역은 한반도 총면적 22만 258㎢의 약 45%인 9만 9720㎢이다.
대한민국의 수도는 서울특별시이며, 행정적으로는 서울특별시, 1개 특별자치시, 6개 광역시, 1개 특별자치도, 8개 도로 구분되어 있다. 총인구는 1988년에 4197만 5000명이었으나 2015년 현재 5061만 7045명이며, 인구밀도는 1988년에는 423명/㎢이었으나 2010년 현재 485명/㎢이다.
대한민국의 국어는 한국어이며, 문자는 한글 전용을 원칙으로 하되 꼭 필요한 경우에 한하여 한자를 병기하고 있다. 통화는 원화(won貨)이며, 국기는 태극기(太極旗), 국가(國歌)는 애국가, 국화는 무궁화이다.
        </p>
      </section>
      <section class="scroll-section" id="scroll-section-2">
        <div class="sticky-elem sticky-elem-canvas">
          <canvas id="video-canvas-1" width="1920" height="1080"></canvas>
        </div>
        <div class="sticky-elem main-message a">
          <p>
            <small>애국가</small>
            안익태
          </p>
        </div>
        <div class="sticky-elem desc-message b">
          <p>
            동해물과 백두산이 마르고 닳도록
하느님이 보우하사 우리나라 만세
무궁화 삼천리 화려 강산
대한 사람 대한으로 길이 보전하세
          </p>
          <div class="pin"></div>
        </div>
        <div class="sticky-elem desc-message c">
          <p>애국가(愛國歌)는<br /> ‘나라를 사랑하는 노래’라는 뜻</p>
          <div class="pin"></div>
        </div>
      </section>
      <section class="scroll-section" id="scroll-section-3">
        <p class="mid-message">
          <strong>대한민국 인구</strong>
          <br />
          대한민국의 인구는 2022년 기준 대략 5,161만 명으로,
          <br />
          아시아 13위, 세계 28위에 해당
        </p>
        <canvas class="image-blend-canvas" width="1920" height="1080"></canvas>
        <p class="canvas-caption">
          1945년~1948년 분단 당시에는 13도 체제를 유지하고 있었으나, 70여 년의 긴 세월 동안 분단되고 남북의 행정구역의 변동이 있었던 관계로 남북통일 시 광역급 행정구역이 더욱 늘어날 것으로 전망된다. 분단 당시 존재한 13도는 경기도, 강원도, 충청남도, 충청북도, 전라남도, 전라북도, 경상남도, 경상북도, 황해도, 평안남도, 평안북도, 함경남도, 함경북도이다.
          한반도 남쪽 바다(남해, 동중국해)에 있는 제주도는 대한민국에서 가장 큰 섬이다. 울릉도 및 독도와 영종도, 서해 5도, 강화도는 전략상 요충지로 간주된다.
          거제도, 남해도, 진도, 완도, 추자도, 거문도도 있다.
          반도 지형으로, 서쪽은 중국, 북쪽은 북한, 동쪽은 일본에 둘러싸여 있고, 아래쪽은 멀리 대만과, 더 아래쪽으로는 동남아 국가 등이 있다.
        </p>
      </section>
      <footer class="footer">
        220124110, 정성주
      </footer>
    </div>
    <script src="./main.js"></script>
  </body>
</html>

'캡스톤디자인 1' 카테고리의 다른 글

4.인터랙션 구현  (0) 2022.05.18
3.CSS작성  (0) 2022.05.18
1.메뉴 스타일링  (0) 2022.05.18
웹페이지 골격 만들기  (0) 2022.04.12
Docker,portainer,nginx  (0) 2022.03.27

HTML에서 한 작업

<link rel="stylesheet" href="css/default.css"/>
공백을 없애여 작업하기 편하게 함


<div class="local-nav-links">
링크연결

<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;900&display=swap">
구글 폰트 불러오기

<link rel="stylesheet" href="css/main.css"/>
main css에 연결


css에서한 작업

overflow-x: hidden;
가로스크롤을 못하게 하여 안전하게

color: rgb(29, 29, 31);
색 설정

letter-spacing: -0.05em;
자간 설정

background: white;
배경색 설정

line-height: 1.6;
행간 설정

max-width: 1000px;
최대폭

margin: 0 auto;
센터 정열

display: flex;
justify-content: space-between;
flex를 이용하여 사이 균일하게 벌리기

.local-nav-links a:not(.product-name) {
margin-left: 2em;
}
괄호안에 있는 조건은 제외시킨다

color: rgb(29, 29, 31);
text-decoration: none;
링크의 컬러와 밑줄을 없앤다

.local-nav-links .product-name {
margin-right: auto;
font-size: 1.4rem;
font-weight: bold;
}
우선순위가 밀려 글씨가 안커지므로
local-nav links.을 붙여 구체적인 클래스를 설정해 주어 우선순위를 높여 준다

'캡스톤디자인 1' 카테고리의 다른 글

3.CSS작성  (0) 2022.05.18
2. HTML 작성  (0) 2022.05.18
웹페이지 골격 만들기  (0) 2022.04.12
Docker,portainer,nginx  (0) 2022.03.27
VMWare 가상 머신, Ubunt설치  (0) 2022.03.27

CSS Flex

 

flex CSS 속성은 하나의 플렉스 아이템이 자신의 컨테이너가 차지하는 공간에 맞추기 위해 크기를 키우거나 줄이는 방법을 설정하는 속성이다

Flex는 레이아웃 배치 전용 기능으로 고안되었다

flex는 flex-grow, flex-shrink, flex-basis의 단축 속성

 

Flex 레이아웃을 만들기 위한 기본적인 HTML 구조

	<div class="container">
	  <div class="item">helloflex</div>
	  <div class="item">abc</div>
	  <div class="item">helloflex</div>
	</div>

부모 요소인 div.container를 Flex Container(플렉스 컨테이너)라고 부르고,
자식 요소인 div.item들을 Flex Item(플렉스 아이템)이라고 부른다

 

Flex의 속성

  • 컨테이너에 적용하는 속성
  • 아이템에 적용하는 속성

 

Flex 컨테이너에 적용하는 속성들

display: flex;

.container {
	display: flex;
	/* display: inline-flex; */
}
  • Flex 아이템들은 가로 방향으로 배치
  • 자신이 가진 내용물의 width만큼만 차지
  • height는 컨테이너의 높이만큼 늘어남

아이템들이 배치된 방향의 축을 메인축(Main Axis),
메인축과 수직인 축을 수직축 또는 교차축(Cross Axis)라고 한다

 

배치 방향 설정
flex-direction

.container {
	flex-direction: row;
	/* flex-direction: column; */
	/* flex-direction: row-reverse; */
	/* flex-direction: column-reverse; */
}

row (기본값)
아이템들이 행(가로) 방향으로 배치된다

row-reverse
아이템들이 역순으로 가로 배치된다

column
아이템들이 열(세로) 방향으로 배치된다

column-reverse
아이템들이 역순으로 세로 배치 된다

 

줄넘김 처리 설정
flex-wrap

컨테이너가 더 이상 아이템들을 한 줄에 담을 여유 공간이 없을 때
아이템 줄바꿈을 어떻게 할지 결정하는 속성이다

.container {
	flex-wrap: nowrap;
	/* flex-wrap: wrap; */
	/* flex-wrap: wrap-reverse; */
}

nowrap (기본값)
줄바꿈을 하지 않는다(넘으면 삐져나감)

wrap
줄바꿈을 한다

wrap-reverse
줄바꿈을 하는데, 아이템을 역순으로 배치한다

 

flex-flow
flex-direction과 flex-wrap을 한꺼번에 지정할 수 있는 단축 속성이다

.container {
	flex-flow: row wrap;
	/* flex-direction: row; */
	/* flex-wrap: wrap; */
}

메인축 방향 정렬
justify-content

.container {
	justify-content: flex-start;
	/* justify-content: flex-end; */
	/* justify-content: center; */
	/* justify-content: space-between; */
	/* justify-content: space-around; */
	/* justify-content: space-evenly; */
}

flex-start
아이템들을 시작점으로 정렬한다

flex-end
아이템들을 끝점으로 정렬한다

center
아이템들을 가운데로 정렬한다

space-between
아이템들의 “사이(between)”에 균일한 간격을 만든다

space-around
아이템들의 “둘레(around)”에 균일한 간격을 만든다

space-evenly
아이템들의 사이와 양 끝에 균일한 간격을 만든다

 

수직축 방향 정렬
align-items

.container {
	align-items: stretch;
	/* align-items: flex-start; */
	/* align-items: flex-end; */
	/* align-items: center; */
	/* align-items: baseline; */
}

stretch (기본값)
아이템들이 수직축 방향으로 끝까지 늘어난다

flex-start
아이템들을 시작점으로 정렬한다
flex-direction이 row(가로 배치)일 때는 위, column(세로 배치)일 때는 왼쪽이다

flex-end
아이템들을 끝으로 정렬한다
flex-direction이 row(가로 배치)일 때는 아래, column(세로 배치)일 때는 오른쪽이다

center
아이템들을 가운데로 정렬한다

baseline
아이템들을 텍스트 베이스라인 기준으로 정렬한다

 

여러 행 정렬
align-content

 

.container {
	flex-wrap: wrap;
	align-content: stretch;
	/* align-content: flex-start; */
	/* align-content: flex-end; */
	/* align-content: center; */
	/* align-content: space-between; */
	/* align-content: space-around; */
	/* align-content: space-evenly; */
}

stretch

아이템들이 수직축 방향으로 끝까지 늘어난다

 

flex-start

아이템들을 시작점으로 정렬한다

 

flex-end

아이템들을 끝으로 정렬한다

 

center

아이템들을 가운데로 정렬한다

 

space-between

아이템들의 “사이(between)”에 균일한 간격을 만든다

 

space-around

아이템들의 “둘레(around)”에 균일한 간격을 만든다

 

space-evenly

아이템들의 사이와 양 끝에 균일한 간격을 만든다

'공부' 카테고리의 다른 글

엑셀 기초 요약  (0) 2024.12.16
Firebase 로그인 구현하기 -웹 #1  (0) 2022.05.19

+ Recent posts