All'alba vincerò

At dawn, I will win!

Toy Projects

[Javascript] 스크롤(scroll) 포트폴리오

나디아 Nadia 2024. 3. 6. 16:31

 


스크롤(scroll) 포트폴리오

: 스크롤을 내려가며 볼 수 있는 포트폴리오

 

 

 



사용 언어

  • HTML
  • CSS
  • Javascript

 


구조

  • index.html - 전체 구조
  • index.js - 기능 구현
  • main.css - 전체 디자인



 


코드

 

구현 계획 & 기능 구현

1. 메뉴바 생성
1-2. 상단에 고정 - position: fixed;
1-3. 서브메뉴 위치 설정 - <a> 태그 이용

 

2. 본문
2-1. 메뉴마다 나누기 - <section> 태그 이용
2-2. 내용 넣기
(1) Home

  • 자기소개 (간략)

(2) About

  • 깃허브, 벨로그 버튼

(3) Skills

  • 가능 언어
  • 가능 프로그램

(4) Projectst

  • 자바 세미 프로젝트 - 캐러셀 슬라이드

(5) Contact me

  • 이메일 주소
  • 연락처

 

3. 스크롤 이벤트
3-1. 스크롤 진행바 넣기

 

 

 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="main.css">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap');
    </style>
</head>
<body>
    <!-- 스크롤 진행바 -->
    <div class="progress"></div>

    <!-- 상단 메뉴 -->
    <nav class="menu">
        <ul class="list-group">
            <li class="list-item">
                <a href="#home">Home</a>
            </li>
            <li class="list-item">
                <a href="#about">About</a>
            </li>
            <li class="list-item">
                <a href="#skills">Skills</a>
            </li>
            <li class="list-item">
                <a href="#projects">Projects</a>
            </li>
            <li class="list-item">
                <a href="#contact">Contact</a>
            </li>
        </ul> 
    </nav>


    <div id="container">
        <!-- 메인 -->
        <section id="home" class="section">
            <div class="title">
                <h2>권<span>보령</span></h2>
                <img src="image.jpg" alt="My image" style="width: 270px; height: 300px;">
                <h4>끊임없이 성장하는 자</h4>
                <p></p>
                <p id="a">안녕하세요,<br/>
                    프론트엔드 개발자 권보령입니다.<br/></P>

                <P id="a">끊임없이 배우며 성장하는 것을 좋아합니다.<br/>
                    스터디를 하며 지식을 나누고
                    개발 블로그를 운영하며 약 70개의 포스팅을 작성하였습니다.
                </p>
                <p> 추리 소설과 같은 매력을 가진 코딩에 흥미가 생겼고, <br/>
                    마크업 언어에 대한 호기심에 혼자 개발을 공부하며 
                    프론트엔드 개발자를 꿈꾸게 되었습니다. <br/>
                </p>
                <p> 수많은 도전과 경험을 통해 다양한 기술 스택을 쌓아 <br/>
                    최고의 UX를 제공할 수 있는 프론트엔드 개발자가 되고 싶습니다.
                </p>
            </div>
        </section>
    
        <!-- About -->
        <section id="about" class="section" style="background-color: rgb(251, 248, 243);">
            <div class="title">
                <h2>About <span id="me">me</span></h2> 
                <!-- 색상을 다르게 주기 위해 <span> 태그 사용 -->
            </div>
            <h4 style="font-size: 20px; text-align: center;">성실의 미덕</h4>
            <p id="a">
                그것이 제 무기입니다.<br/>
                꾸준히, 조금씩, 길게 떨어지는 물방울이 결국 바위를 부식시키는 것처럼, <br/>
                아무리 어렵고 힘든 일이라도 성실한 물방울이 된다면 해내지 못할 일이 없다고 생각합니다.
            </p>
            <p id="a">
                저는 이러한 제 신조에 맞게 곧게 살아가려고 항상 노력하는 사람입니다. <br/>
                작은 일도 성실하게, 한번 시작한 일은 끝까지 책임지고 마무리하는 것을 좋아합니다.
            </p>
            <div class="iconabout">
                <a href="https://velog.io/@kwonboryong/posts">
                    <svg style="width: 90px; height: 90px;" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Velog</title><path d="M3 0C1.338 0 0 1.338 0 3v18c0 1.662 1.338 3 3 3h18c1.662 0 3-1.338 3-3V3c0-1.662-1.338-3-3-3H3Zm6.883 6.25c.63 0 1.005.3 1.125.9l1.463 8.303c.465-.615.846-1.133 1.146-1.553.465-.66.893-1.418 1.283-2.273.405-.855.608-1.62.608-2.295 0-.405-.113-.727-.338-.967-.21-.255-.608-.577-1.193-.967.6-.765 1.35-1.148 2.25-1.148.48 0 .878.143 1.193.428.33.285.494.704.494 1.26 0 .93-.39 2.093-1.17 3.488-.765 1.38-2.241 3.457-4.431 6.232l-2.227.156-1.711-9.628h-2.25V7.24c.6-.195 1.305-.406 2.115-.63.81-.24 1.358-.36 1.643-.36Z"/></svg>
                </a>
                <a href="https://github.com/kwonboryong">
                    <svg style="width: 90px; height: 90px;" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
                </a>
            </div>
        </section>
        
        <!-- skills -->
        <section id="skills" class="section">
            <div class="title">
                <h2>Skills</h2> 
                <h4>가능한 언어</h4>
                <p id="a">HTML, CSS, Javascript, Java</p>
                <div class="icon">
                    <img alt="Html" src ="https://img.shields.io/badge/HTML5-E34F26.svg?&style=for-the-badge&logo=HTML5&logoColor=white"/> 
                    <img alt="Css" src ="https://img.shields.io/badge/CSS3-1572B6.svg?&style=for-the-badge&logo=CSS3&logoColor=white"/> 
                    <img alt="JavaScript" src ="https://img.shields.io/badge/JavaScript-F7DF1E.svg?&style=for-the-badge&logo=JavaScript&logoColor=black"/> 
                    <img src="https://img.shields.io/badge/java-3CB371?style=for-the-badge&logo=OpenJDK&logoColor=white">
                </div>
                
                <h4 id="untitle">가능한 프로그램</h4>
                <p id="a">VS-code, Eclipse, Intelli-J, Oracle</p>
                <div>
                    <svg style="width: 70px; height: 70px" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Visual Studio Code</title><path d="M23.15 2.587L18.21.21a1.494 1.494 0 0 0-1.705.29l-9.46 8.63-4.12-3.128a.999.999 0 0 0-1.276.057L.327 7.261A1 1 0 0 0 .326 8.74L3.899 12 .326 15.26a1 1 0 0 0 .001 1.479L1.65 17.94a.999.999 0 0 0 1.276.057l4.12-3.128 9.46 8.63a1.492 1.492 0 0 0 1.704.29l4.942-2.377A1.5 1.5 0 0 0 24 20.06V3.939a1.5 1.5 0 0 0-.85-1.352zm-5.146 14.861L10.826 12l7.178-5.448v10.896z"/></svg>
                    <svg style="width: 70px; height: 70px" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Eclipse IDE</title><path d="M11.109.024a15.58 15.58 0 00-.737.023C6.728.361 3.469 2.517 1.579 5.86A12.53 12.53 0 00.021 11.11c-.04.517-.02 1.745.035 2.208.306 2.682 1.353 5.06 3.07 6.965 1.962 2.173 4.586 3.467 7.437 3.663.42.032 1.043.04 1.02.012a2.404 2.404 0 00-.338-.074c-1.674-.33-3.388-1.13-4.777-2.232a12.344 12.344 0 01-2.45-2.636A12.387 12.387 0 011.884 12.5a12.413 12.413 0 01.56-4.274c.785-2.522 2.37-4.726 4.475-6.228A11.073 11.073 0 0111.156.122l.443-.098zm1.474.51C10.646.65 8.807 1.299 7.301 2.4 5.426 3.77 3.995 5.644 3.22 7.746c-.145.397-.282.82-.282.879 0 .012 3.828.024 10.31.024 8.463 0 10.315-.008 10.315-.036 0-.047-.153-.525-.283-.878-.153-.42-.576-1.31-.82-1.722-.4-.683-.91-1.373-1.474-1.992-1.65-1.82-3.593-2.934-5.82-3.334-.785-.141-1.8-.2-2.585-.153zM23.83 9.97c-.02 0-4.792 0-10.609.004l-10.573.008-.011.059c-.036.16-.134 1.081-.134 1.242 0 .028 1.785.032 10.746.032H24v-.075c0-.102-.07-.791-.106-1.054-.02-.16-.04-.216-.063-.216zm-10.573 2.635c-9.37-.004-10.73 0-10.742.035-.02.04.024.557.075.973.02.157.035.298.035.314 0 .027 2.137.035 10.624.035h10.624l.024-.188c.043-.326.102-.97.094-1.067l-.008-.094zm.003 2.718c-8.882 0-10.321.004-10.321.035 0 .02.054.208.12.42a11.122 11.122 0 002.072 3.741c.282.342.945 1.036 1.228 1.287 1.568 1.4 3.247 2.216 5.18 2.53.605.094.886.113 1.75.11.91 0 1.297-.032 2.023-.177 2.11-.416 3.914-1.451 5.53-3.17 1.267-1.348 2.106-2.76 2.628-4.41l.117-.366z"/></svg>
                    <svg style="width: 70px; height: 70px" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>IntelliJ IDEA</title><path d="M0 0v24h24V0zm3.723 3.111h5v1.834h-1.39v6.277h1.39v1.834h-5v-1.834h1.444V4.945H3.723zm11.055 0H17v6.5c0 .612-.055 1.111-.222 1.556-.167.444-.39.777-.723 1.11-.277.279-.666.557-1.11.668a3.933 3.933 0 0 1-1.445.278c-.778 0-1.444-.167-1.944-.445a4.81 4.81 0 0 1-1.279-1.056l1.39-1.555c.277.334.555.555.833.722.277.167.611.278.945.278.389 0 .721-.111 1-.389.221-.278.333-.667.333-1.278zM2.222 19.5h9V21h-9z"/></svg>
                    <svg style="width: 70px; height: 70px" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Oracle</title><path d="M16.412 4.412h-8.82a7.588 7.588 0 0 0-.008 15.176h8.828a7.588 7.588 0 0 0 0-15.176zm-.193 12.502H7.786a4.915 4.915 0 0 1 0-9.828h8.433a4.914 4.914 0 1 1 0 9.828z"/></svg>
                </div>
            </div>
        </section>
        
        <!-- projects -->
        <section id="projects" class="section">
            <div class="title">
                <h2>Projects</h2> 
                <h4>지하철 혼잡도 관리 시스템</h4>
                <p style="font-size: 17px; margin-top: -10px;">2024-01-29 ~ 2024-02-08</p>
                <p id="a">지하철 혼잡도 제공을 통한 역 혼잡도 관리</p>

                <!-- 캐러셀 슬라이드 -->
                <div style="overflow: hidden;">
                    <div class="slide-container">
                        <div class="slide-box">
                            <img style="width: 600px; height: 350px;" src="project.png" alt="project">
                        </div>
                        <div class="slide-box">
                            <img style="width: 600px; height: 350px;" src="project2.png" alt="project">
                        </div>
                        <div class="slide-box">
                            <img style="width: 600px; height: 350px;" src="project3.png" alt="project">
                        </div>
                    </div>
                </div>
            
                <div class="btn-slide">
                    <button class="slide-1">1</button>
                    <button class="slide-2">2</button>
                    <button class="slide-3">3</button>
                </div>
                <div class="btn-next">
                    <button class="before">이전</button>
                    <button class="next">다음</button>
                </div>
            </div>
        </section>
        
        <!-- contact -->
        <section id="contact" class="section" style="background-color: rgb(251, 248, 243);">
            <div class="title">
                <h2>Contact <span id="me">me</span></h2> 
                <h4>Email</h4>
                <p id="a">kwonboryong@naver.com</p>
                <h4 id="untitle">Phone</h4>
                <p id="a">010-1234-1234</p>
            </div>
        </section>
    </div>
            
    <script src="index.js"></script>
</body>
</html>

 

 

 

index.js

// 스크롤 진행바
window.addEventListener('scroll', function() {
    
    var sHeight = document.querySelector('html').scrollHeight;
    var cHeight = document.querySelector('html').clientHeight;
    var sTop = document.querySelector('html').scrollTop;

    const prg = ((sTop + cHeight) / sHeight) * 100;
    // document.querySelector('.progress').style.width = progress + "%";

    console.log(prg);

    if (prg < 17) {
        this.document.querySelector('.progress').style.width = '0%';
    } else if (prg < 22) {
        this.document.querySelector('.progress').style.width = '20%';
    } else if (prg < 40) {
        this.document.querySelector('.progress').style.width = '30%';
    } else if (prg < 65) {
        this.document.querySelector('.progress').style.width = '40%';
    } else if (prg < 75) {
        this.document.querySelector('.progress').style.width = '60%';
    } else if (prg < 80) {
        this.document.querySelector('.progress').style.width = '80%';
    } else if (prg > 95) {
        this.document.querySelector('.progress').style.width = '100%';
    }
});

// 캐러셀 슬라이드
// 숫자 버튼
/* 2번 버튼 클릭 시 - 2번 사진 가져오기(1번 사진을 왼쪽으로 밀기) */
document.getElementsByClassName('slide-2')[0].addEventListener('click', function() {
    document.querySelector('.slide-container').style.transform = 'translateX(-100vw)'
    now = 2;
    // ***숫자 버튼에서도 현재 사진 변수(now)를 신경 써야 한다!
});

// 3번 버튼
document.getElementsByClassName('slide-3')[0].addEventListener('click', function() {
    document.querySelector('.slide-container').style.transform = 'translateX(-200vw)'
    now = 3;
});

// 1번 버튼
document.getElementsByClassName('slide-1')[0].addEventListener('click', function() {
    document.querySelector('.slide-container').style.transform = 'translateX(0vw)'
    now = 1;
});


// 다음 버튼
var now = 1; // 현재 사진 변수

document.querySelector('.next').addEventListener('click', function() {

    if (now == 3) { // 마지막 장에서 '다음'을 누르면 첫 번째 장이 나오도록
        document.querySelector('.slide-container').style.transform = 'translateX(0vw)'
        now = 1;
    } else {
        document.querySelector(".slide-container").style.transform = "translateX(-" + now + "00vw)";
        now++;
    }
});


// 이전 버튼
document.querySelector('.before').addEventListener('click', function() {

    if (now == 1) { // 첫 번째 장에서 '이전'을 누르면 마지막 장이 나오도록
        document.querySelector('.slide-container').style.transform = 'translateX(-200vw)'
        now = 3;
    } else {
        document.querySelector(".slide-container").style.transform = "translateX(-" + (now - 2) + "00vw)";
        now--;
    }
});

 

 

 

main.css

body {
    margin: 0;
    background-color: var(--bodybackground-color);
    font-family: "Gowun Dodum", sans-serif;
}


/* a태그 밑줄 없애기 */
a {text-decoration-line: none; color: rgb(187, 26, 5);}

/* 스크롤 진행바 */
.progress {
    background-color: red;
    padding: 1px;
    width: 0%;
    position: fixed;
    z-index: 10;
    transition: all 1s;
    margin-top: -85px;
}

/* 상단바*/
.menu {
    width: 100%;
    display: flex; /* 가로로 정렬 */
    justify-content: space-between; /* 박스 간 간격 */

    align-items: center; /* 가운데 정렬 */
    background-color: antiquewhite;

    height: 95px;
    margin-top: -86px;
    position: fixed; /* 스크롤 고정 */
}

/* 서브메뉴 - 그룹 */
.list-group {
    font-size: 18px;
    list-style:none; /* 목록 점 없애기 */
    display: flex; /* 가로로 정렬 */   
    margin: 0 auto; /* 가운데 정렬*/
    padding-left: 0;
}  

/* 서브메뉴 - 개인 */
.list-item {
    padding: 8px 70px; /* 메뉴 간 간격 */
    cursor: pointer;
}

/* 메뉴 제목 */
.title {
    margin-top: 85px;
    padding-top: 70px;
    padding-bottom: 10px;
    width: auto;
    font-size: 20px;
    text-align: center;
    display: grid;
}

/* 섹션 당 한 화면 보여주기 */
.section {
    height: 100vw;
}

/* 본문 - 작은 내용 */
#a {
    font-size: 20px;
    margin-top: -10px;
    text-align: center;
}

/* 두 번째 본문 - 제목 */
#untitle {
    margin-top: 40px;

}

/* 메뉴 간격 조정 */
#about {
    padding-top: 2px;
}

#skills {
    padding-top: 2px;
}

#projects {
    padding-top: 2px;
}

#contact {
    padding-top: 2px;
}

#me {color: rgb(240, 35, 25);}


/* 프로필 사진 */
.title img {
    margin: 0 auto;
}

/* 벨로그, 깃허브 아이콘 */
.iconabout {
    text-align: center;
    margin-top: 60px;
}

/* 캐러셀 슬라이드 */
.slide-container {
    width: 300vw; 
    transition: all 1s;
}

.slide-box {
    width: 100vw;
    float: left;
}

.slide-box img {
    width: 100%;
}

/* 숫자 버튼 */
.btn-slide {
    text-align: center;
    padding: 40px;
}

.slide-1, .slide-2, .slide-3 {
    font-family: "Nanum Myeongjo", serif;
    text-align: center;
    font-size: 15px;

    margin: 0px 5px 0px 10px;
    width: 27px;
    height: 25px;
    border: none;
    background-color: rgb(228, 234, 239);
    box-shadow: 1px 2px 1px rgb(172, 172, 172), 1px 1px 0px rgb(237, 237, 237);
}

.slide-1:hover, .slide-2:hover, .slide-3:hover {
    background-color: aliceblue;
}

/* 다음, 이전 버튼 */
.btn-next {
    font-family: "Nanum Myeongjo", serif;
    text-align: center;
}

.next, .before {
    font-family: "Nanum Myeongjo", serif;
    text-align: center;
    font-size: 15px;

    margin: 0px 5px 0px 10px;
    width: 50px;
    height: 27px;
    border: none;
    background-color: rgb(223, 238, 251);
    box-shadow: 1px 2px 1px rgb(172, 172, 172), 1px 1px 0px rgb(237, 237, 237);
}

.next:hover, .before:hover {
    background-color: aliceblue;
}

 

 

 



잘한 점

  • 지금까지 배운 기능들을 잘 녹여서 구현한 것!
    - 상단바, 스크롤 진행바, 메뉴 클릭 시 자동 이동, 캐러셀 슬라이드 등 내가 배우고 구현할 수 있는 기능들로 만들어보니 재밌었다!

 

  • css를 내 손으로 구현한 것
    - 사실 js로 기능을 구현하는 것보다는 css로 디자인하는게 제일 힘들고 시간이 많이 걸렸다. 더 예쁘게 만드려면 css 사이트나 라이브러리에서 코드를 긁어오는게 맞는데 궁극적으로는 css도 실력을 키워야 하니까... 포기하지 않고 끝까지 내 손으로 구현한게 뿌듯하다.

 




아쉬운 점

  • 원하는 디자인을 다 구현하지 못했다.
    css는...아직도 어려운 것 투성이다. 좀 익숙해졌다 싶다가도 낯설고 알다가도 모르겠다.
    꾸준히 정진해야겠다.

 

 


 

깃허브

https://github.com/kwonboryong/Toy_Projects/tree/main/Scroll_mySelf





참고

https://vannilla-js-basic-project-10-scroll.netlify.app/

https://parkjh7764.tistory.com/46
https://hianna.tistory.com/474
https://codingbroker.tistory.com/56
https://romanticdeveloper.tistory.com/58