인스타 UI클론 코딩 제출

김하진·2022년 5월 2일

일단은 제출시간이 임박히 급히 마무리 하였다. 아쉬운점도 많았고 배울 점 도 많았던 시간이였던 것 같다

https://drive.google.com/file/d/1lX6TC6TGiw915lx1FroU6CWx9hxU7AKd/view?usp=sharing
<동영상 링크 입니다>
https://github.com/haajinkim/instagram_clon
깃허브 링크

hede 부분

<div class="body">
    <div class="head">
        <i class="fa-solid fa-magnifying-glass search_icon"></i>
        <input id="input_box" type="search" class="head_input" placeholder="검색"/>
        <div class="head_items">
            <i class="fa-solid cursor fa-house fa-2x"
               onclick="window.location.reload(); location.href='index.html'"></i>
            <i class="fa-regular head-regular fa-paper-plane fa-2x"></i>
            <i class="fa-regular head-regular fa-square-plus fa-2x"></i>
            <i class="fa-regular head-regular fa-compass fa-2x"></i>
            <i class="fa-regular head-regular fa-heart fa-2x"></i>
            <img src="../static/image/hj.jpg"
                 style="margin-left: 5%; width: 30px; height: 30px; border-radius: 10px; cursor: pointer;">
        </div>
    </div>
</div>

head css

.page {
    background-color: whitesmoke;
    margin-left: 0;
    margin-right: 0;
}

.html {
    width: 100%;
    margin: 0;
    padding: 0;
}

.head {
    height: 70px;
    background-color: white;
    background-image: url("../static/image/head_image.png");
    background-repeat: no-repeat;
    background-size: 150px;
    background-position: 32%;
    border-top: 1px solid lightgray;
    border-bottom: 1px solid lightgray;
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 50;
}


.head_input {
    background-color: whitesmoke;
    width: 10%;
    height: 50%;
    margin-left: 45%;
    margin-top: 20px;
    outline: 0;
    text-align: center;
    border-radius: 10px;
    border: white;
}

.head-regular, .cursor, .cursor_1 {
    cursor: pointer;
}

.head_items {
    margin-left: 3%;
    margin-top: 20px;
    display: flex;
}


.head-regular {
    margin-left: 15px;
}

.head, .head_input {
    display: flex;

}

.search_icon {
    position: absolute;
    display: inline-block;
    margin-left: 45.5%;
    margin-top: 30px;
    color: gray;
    cursor: text;


}


@media (max-width: 720px) {
    .head_input {
        display: None;
    }
}

@media (max-width: 720px) {
    .head_items, .head {
        display: flex;
        width: 100%;
        background-position: 0%;

    }
}

@media (max-width: 720px) {
    .head_items {
        display: flex;
        justify-content: flex-end;
        margin-top: 5%;
        font-size: 90%;
    }    

head js

const head_input = document.querySelector(".head_input");
const search_icon = document.querySelector(".search_icon");
head_input.addEventListener('focus', (event) => {
    search_icon.style.visibility = "hidden";
})
head_input.addEventListener('focusout', (e) => {
    search_icon.style.visibility = "visible";
})
  • 우선 head 부분은 이렇게 구성을 하였습니다 . 어려웠던 점은, 역시 배치였던 것 같습니다. 또한 heae 부터 css파일을 나눠서
    최대한 코드작업을 하기 편하게 작업을 이어 나갔습니다. 사진에 보이는 것 처럼 heae부분은 미디어 쿼리로 어느 정도 구현을 하였습니다. position 과 display 에 대해서 어느정도는 알게 된 작업 이였던 것 같습니다. 그렇게 많이 어렵지는 않았습니다.
    또한 head부분도 js를 이용해서 검색박스 클릭시 아이콘을 없애주는 기능을 넣었다. 이부분은 팀원인 정환님의 도움을 조금 받았는데 이 js 문법이 하나 풀리고 나니깐 나머지 js 작업은 조금 수월하게 작업을 한 것 같다.

story

<div class="story">
    <img src="../static/image/roopy.png" class="page_image" style="margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 10%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 20%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 30%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 40%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 50%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 60%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 70%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 80%; margin-top: 2%;">
    <img src="../static/image/roopy.png" class="page_image" style="left: 90%; margin-top: 2%;">
</div>
<div>

story 부분은 하드코딩으로 일단은 붙여 놓았습니다. 제일 마지막에 시도했던 부분이기도 하고, 우선은 UI만 간략하게 구성을 하였습니다.

 <footer>
            <img class="footer_profile" src="../static/image/hj.jpg">
            <p class="footer_profile_name">star_and_jinkim</p>
            <p class="footer_profile_name2">김하진</p>
            <button class="profile_button">전환</button>
            <button class="footer_prbtn">회원님을 위한 추천</button>
            <button class="footer_prbtn2">모두 보기</button>
            <p class="footer_name1">rion man</p>
            <p class="footer_insta1">instagram 신규 가입</p>
            <button class="follow1">팔로우</button>
            <p class="footer_name2">old boy</p>
            <p class="footer_insta2">instagram 신규 가입</p>
            <button class="follow2">팔로우</button>
            <p class="footer_name3">nobonobono</p>
            <p class="footer_insta3">instagram 신규 가입</p>
            <button class="follow3">팔로우</button>
            <p class="footer_name4">taeri_kim</p>
            <p class="footer_insta4">instagram 신규 가입</p>
            <button class="follow4">팔로우</button>
            <p class="footer_name5">ananan</p>
            <p class="footer_insta5">instagram 신규 가입</p>
            <button class="follow5">팔로우</button>
            <img class="footer_img1" src="../static/image/rion.jpg">
            <img class="footer_img2" src="../static/image/old1.jpg">
            <img class="footer_img3" src="../static/image/bonobono.jpg">
            <img class="footer_img4" src="../static/image/taeri.jpg">
            <img class="footer_img5" src="../static/image/roopy2.jpg">
            <p><a class="footer_text" href="https://about.instagram.com/">소개.</a></p>
            <p><a class="footer_text2" href="https://help.instagram.com/">도움말.</a></p>
            <p><a class="footer_text3" href="https://about.instagram.com/blog/">홍보센터.</a></p>
            <p><a class="footer_text4" href="https://developers.facebook.com/docs/instagram">API.</a></p>
            <p><a class="footer_text5" href="https://about.instagram.com/about-us/careers">채용정보.</a></p>
            <p><a class="footer_text6"
                  href="https://help.instagram.com/519522125107875/?maybe_redirect_pol=0">개인정보처리방침.</a>             </p>
            <p><a class="footer_text7" href="https://help.instagram.com/581066165581870">약관.</a></p>
            <p><a class="footer_text8" href="https://www.instagram.com/explore/locations/">위치.</a></p>
            <p><a class="footer_text9" href="https://www.instagram.com/directory/profiles/">인기계정.</a></p>
            <p><a class="footer_text10" href="https://www.instagram.com/directory/hashtags/">해쉬태그.</a></p>
            <p><a class="footer_text11" href="https://about.instagram.com/">언어.</a></p>

            <address class="footer_text_under">© 2022 INSTAGRAM FROM META</address>
        </footer>

footer.css

footer. {
    display: flex;
   top: 50%;
}

.footer_profile {
    width: 60px;
    height: 60px;
    margin-top: -120%;
    border-radius: 70%;
}
.footer_profile_name {
    margin-left: 63%;
    margin-top: -90%;
    font-weight: bold;
    
.profile_button {
    position: absolute;
    top: 10%;
    left: 67%;
    border: none;
    background-color: whitesmoke;
    color: #0095ff;
    font-size:13px;
    font-weight: bold;
}    
    
.footer_name1 {
    position: absolute;
    top: 20%;
    left: 59%;
    font-weight: bold;
}
.follow1 {
    position: absolute;
    top: 21.2%;
    left: 66%;
    border: none;
    background-color: whitesmoke;
    color: #0095ff;
    font-size:13px;
    font-weight: bold
}
.footer_text {
    position: absolute;
    top: 45.5%;
    left: 57%;
    font-size: 13px;
    color: darkgrey;
}
  • footer 부분인 생각보다 손이 많이 갔다. 각 태그들을 position absolute 로 개개인 별로 class 로 줘서 작업을 하다보니
    시간이 조금 오래 걸린 것 같다. 제일 짧은 page에 제일 많은 css가 들어갔다. 이것들을 통합으로 관리해서 좀 깔끔하게 코드를 짤 수 있는 방법이 있을까. 이렇게 봐도 코드가 너무지저분하다..

footer 부분은 css부분 코드만 300줄 이므로 대표적인 것들만 가져와 보았다.

main page(feed)

<div class="page_1">
        <img src="../static/image/roopy.png" class="page_image">
        <p class="profile_text">미래의 해적왕</p>
        <div id="carouselExampleIndicators" class="carousel slide" data-bs-ride="carousel">
            <div class="carousel-indicators">
                <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="0" class="active"
                        aria-current="true" aria-label="Slide 1" style="background-color: gray;"></button>
                <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="1"
                        aria-label="Slide 2" style="background-color: gray"></button>
                <button type="button" data-bs-target="#carouselExampleIndicators" data-bs-slide-to="2"
                        aria-label="Slide 3" style="background-color: gray"></button>
            </div>
            <div class="carousel-inner">
                <div class="carousel-item active">
                    <img src="../static/image/roopy2.jpg" class="d-block w-100" alt="...">
                </div>
                <div class="carousel-item">
                    <img src="../static/image/roopy3.jpg.crdownload" class="d-block w-100" alt="...">
                </div>
                <div class="carousel-item">
                    <img src="../static/image/roopy4.jpg" class="d-block w-100" alt="...">
                </div>
            </div>
            <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleIndicators"
                    data-bs-slide="prev">
                <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                <span class="visually-hidden">Previous</span>
            </button>
            <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleIndicators"
                    data-bs-slide="next">
                <span class="carousel-control-next-icon" aria-hidden="true"></span>
                <span class="visually-hidden">Next</span>
            </button>
            <div class="page_icons">
                <i class="fa-regular fa-heart fa-2x "></i>
                <i class="fa-solid fa-comment-dots fa-2x" style="margin-left: 20%;"></i>
                <i class="fa-regular fa-paper-plane fa-2x" style="margin-left: 20%;"></i>
                <i class="fa-solid fa-bookmark fa-2x" style="margin-left: 450%;"></i>
            </div>
            <div class="small_image">
                <img src="../static/image/taeri.jpg" style="width: 20px; height: 20px; border-radius: 70%;"
                     class="small_image1">
                <img src="../static/image/rion.jpg" style="width: 20px; height: 20px; border-radius: 70%;"
                     class="small_image2">
                <img src="../static/image/bonobono.jpg" style="width: 20px; height: 20px; border-radius: 70%;"
                     class="small_image3">
                <p class="icon_text"> &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp <span style="font-weight:bold; ">roopy</span><span style="font-weight:bold; ">외 225명</span>이 좋아합니다</p>
                <div class="text_dec">
                    <p class="feed-article">Monkey.D.Luffy 내 어린 시절 우연히
                        들었던 믿지못할 한마디
                        이 세상을&nbsp 다준다는 매혹적인 얘기
                        내게 꿈을 심어주었어
                        말도 안돼 고개 저어도
                        내 안에 나 나를 보고 속삭여
                        세상은 꿈꾸는 자의 것이라고
                        용기를 내 넌 할 수 있어
                        쉼 없이 흘러가는 시간
                        이대로 보낼 수는 없잖아
                        함께 도전하는 거야
                        너와 나 두 손을 잡고</p>
                    <button class="feed-article-button">more</button>
                    <p style="color: gray" class="cursor_1"> 댓글 31개 모두 보기</p>
                    <ul class="items">
                        <li class="item">
                            <span class="itemText">Luffy 내이름은 몽키 D. 루피 ! ! !</span>
                            <i class="fa-regular head-regular fa-heart itemDel"></i>
                        </li>
                    </ul>

                </div>
                <div>
                    <input type="text" class="page_input" placeholder="             댓글 달기..."/>
                    <i class="fa-solid fa-face-smile fa-2x page_input_icon"></i>
                    <i class="page_input_texticon">
                        <button class="input_button">게시</button>
                    </i>
                </div>
            </div>
        </div>
    </div>

page.css

.page_1 {
    margin-top: 8%;
    margin-left: 25%;
    width: 30%;
    height: 1050px;
    background-color: white;
    border: 1px solid lightgray;
    overflow: hidden;
}
.page_image {
    position: absolute;
    width: 50px;
    height: 50px;
    margin: 10px;
    border: 3px solid transparent;
    border-radius: 50%;
    background-image: linear-gradient(#fff, #fff),
    linear-gradient(to right, red 0%,  orange 100%);
    background-origin: border-box;
    background-clip: content-box, border-box;
    cursor: pointer;
}
.profile_text {
    position: relative;
    top: 2%;
    margin-left: 9%;
    font-weight: bolder;
    cursor: pointer;
}
.carousel-item {
    top: 5%;

}
.carousel-inner {
    height: 650px;
}
.carousel-indicators {
 top: 100%;
}
.page_icons {
    position: absolute;
    margin-top: 2%;
    margin-left: 2%;
    display: flex;
    cursor: pointer;
}
.small_image {
    position: absolute;
    top: 110%;
    left: 5%;

    display: flex;
}
.feed-article{
    font-weight: bold;
    width: 560px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    margin-bottom: 0;
}
.feed-article-button {
  display: inline;
  cursor: pointer;
  color: #777;
  position: absolute;
    border: none;
    background-color: white;
}
@media (max-width: 720px) {
    .footer, .search_icon {
    display: none !important;
    }
}
@media (max-width: 720px) {
    .page_1  {
       margin-top: 20%;
        width: 100%;
        height: 890px;
        margin-left: -0%;
    }
}


@media (max-width: 720px) {
    .page_image {
        width: 10%;
        height: 40px;
        border-radius: 70%;
        margin-top: 3%;
        margin-left: 3%;
    }
 }

@media (max-width: 720px) {
        .page_button {
        font-size: 30px;
        color: black;
        border: none;
        background-color: white;
        margin-left: 90%;
        position: absolute;
        cursor: pointer;
    }
 }

@media (max-width: 720px) {
    .profile_text {
        position: relative;
        margin-left: 15%;
        top: 2.5%;
        font-weight: bolder;
        cursor: pointer;
    }
}

@media (max-width: 720px) {
    .carousel-inner {
        margin-top: 10%;
       height: 100%;
    }
}

head js

const page_input = document.querySelector(".page_input");
const page_input_icon = document.querySelector(".page_input_icon");
page_input.addEventListener('focus', (event) => {
    page_input_icon.style.visibility = "hidden";
})
page_input.addEventListener('focusout', (e) => {
    page_input_icon.style.visibility = "visible";
})

아이콘 감추기

const article = document.querySelector(".feed-article");
const article_button = document.querySelector(".feed-article-button");
article_button.onclick = () => {
    article.style.overflow = "visible";
    article.style.textOverflow = "''";
    article.style.whiteSpace = "normal";
    article.style.width = "640px";
    article_button.style.display = "none";
}

이부분은 게시물 더보기 기능이다. 중요한것은 text-overflow: ellipsis; white-space: nowrap; 부분이였다. 그리고 이것을 px로 조정을 해준것이다. 그리고 버튼은 display none; 으로 버튼을 사라지게 만들어주었다.

  • 메인 page부분도 코드를 간추려서 가져왔다. 중복되서 값만 수정하는 부분이 많기 때문이다. 그만큼 하드코딩이 많다는 증거이다.
    feed 부분이 작업학기가 특히 어려웠다. 한개의 요소를 넣을때마다 위치나 값들을 계속 수정을 해줘야해서 시간이 많이 들었던 부분같다. 또한 메인기능이 3개나 들어가있다. 캐러셀과 검색 더보기 기능. 이부분을 바닐라js 로 구현하는데 시간이 많이 들은 것 같다. 더보기 기능에서도 시간을 많이 썻는데 아이콘 이미지 없애는 기능을 응용해서 구글링 없이 직접 구현했다. 이부분에는 정말 뿌듯했고 많은 공부가 됬던 시간이였다. 또한 헤드부분 서치아이콘 없애는 것과 같은 방식으로 input 박스안에 있는 아이콘을 없애 주었다.

modal.css , html

.modal_wrap {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    align-items: center;
    justify-content: center;
    z-index: 3;
    display: none;

}
.modal {
    background: white;
    width: 18%;
    height: 35%;
    left: 30%;
    top: 20%;
    border-radius: 20px;
    display: flex;

}
.modal_open {
    position: absolute;
    font-size: 30px;
    color: black;
    border: none;
    background-color: white;
    margin-top: 4.3%;
    top:15.4%;
    left: 53%;
    bottom: 100%;
}

.modal_button1 {
    width: 100%;
    height: 58px;
    background-color: white;
    border-bottom: 1px;
    border-top: none;
    border-left: none;
    border-right: none;
    color: red;
    font-weight: bold;
}

.modal_open {
    position: absolute;
    font-size: 30px;
    color: black;
    border: none;
    background-color: white;
    top: 7.4%;
    left: 53%;
    bottom: 100%;
}@media (max-width: 720px) {
    .modal_open {
    position: absolute;
    font-size: 30px;
    color: black;
    border: none;
    background-color: white;
    top: 11%;
    left: 90%;
    }
 }
<div class="modal_wrap">
   <div class="modal">
       <div class="modal_group">
           <button class="modal_button1">신고</button>
           <button class="modal_button2">팔로우 취소</button>
           <button class="modal_button3">게시물로 이동</button>
           <button class="modal_button4">태그된 계정</button>
           <button class="modal_button5">공유 대상...</button>
           <button class="modal_button6">링크 복사</button>
           <button class="modal_button7">퍼가기</button>
           <button id="modal_close" class="modal_button8">취소</button>
       </div>
   </div>
</div>
const open = document.querySelector(".modal_open");
const close = document.getElementById("modal_close");
const modal = document.querySelector(".modal_wrap");
open.onclick = () => {
    modal.style.display = "flex";
};
close.onclick = () => {
    modal.style.display = "none";
};
  • 모달부분도 생각보다는 어렵지 않아서 다행이였다. 역시 찾아보고, 적용해보고 하는데 시간이 많이 걸렸던 것 같다. 모달부분도 js 기능을 통해서 onclik 을 이용하였다. display flex 와 none 을 이용해서 화면에 나타나고 가려지고 하는 기능으로 작업을 시작하였다. 모달부분은 처음에 버튼을 page안에 만들어놨는데 모달기능을 넣을때 이 버튼이 동작을 안하는 것이였다. 아마 같은 div안에 있어야 동작이 정상적으로 실행되는 듯 싶다. 아니면 내가 js 설계를 잘못했을 수도 있다.

어려웠던 댓글창 부분

const input = document.querySelector('.page_input');
const itemAdd = document.querySelector('.input_button');
const items = document.querySelector('.items');

const onAdd = () => {
    const text = input.value;
    if (input.value === '') {
        input.focus();
        return;
    }

    const item = document.createElement('li');
    item.setAttribute('class', 'item');


    const itemText = document.createElement('span')
    itemText.setAttribute('class', 'itemText');
    item.innerText = text;
    itemText.innerHTML = '<i class="fa-regular head-regular fa-heart "></i>';



    item.appendChild(itemText);
    items.appendChild(item);
    input.value = '';
    input.focus();

};
    itemAdd.addEventListener('click', () => {
    onAdd();
});
    input.addEventListener('keypress', (event) =>{
    if (event.key ==='Enter') {
        onAdd();
    }
});
  • 구글링을 통해서 구현하긴 했지만, 정말 여러번의 시도를 통해서 구현을 성공했다. 정말 개인적으로 오래 걸렸던 부분인 것 같다.
    간략히 설명하자면 querySelector 로 클래스 를 받아와서 input 박스의 value의 값을 받아온다. createelement 로 text오와 icon을 생성해준다. 을 그려주는 것이다. 그리고 appendChild 를 통해서 그려주는것이 핵심.
    클릭 이벤트와 keypress -> enter 를 통해서 작동이 되도록 설계를 해놓았다.
profile
진킴

1개의 댓글

comment-user-thumbnail
2022년 5월 4일

안녕하세요 하진님, 김준태 튜터입니다!
코드를 살펴보았는데요, 몇 가지 부분만 보완하시면 좋을 것 같습니다.

  1. html 태그 내부에다가 style="" 이렇게 작성하시는건 지양하시는게 좋습니다! 당장 작성할 때는 편한데요, 프로젝트가 커지게 되면 관리하기가 어려워 집니다.
  2. footer 태그 부분은 내부를 div 를 통해서 조금 나누신 후에 작성하셨다면 더 좋았을 것 같습니다! 코드의 유지가능성을 고려한다면 가독성이 높은 것도 중요합니다!

이외에는 파일 분리도 잘하셨고, 전체적으로 잘 작성하셨습니다. 수고많으셨어요!

답글 달기