프로그래머스 고양이 사진 검색 사이트 - 개발 (CSS)

Z6su3·2022년 4월 21일
0

main.js ← App.js ← api/api.js
← components(floder) ← SearchInput.js
← SearchError.js
← SearchKeyword.js
← SearchResult.js
← ImageInfo.js
← ImageBanner.js
← Loading.js
← DarkMode.js
← lib ← LocalStorage.js
← LazyLoading.js

🐇 DarkMode

  • 기존 CSS의 모든주석을 제거 하고 모든 글자는 #FFFFFF, 배경은 #000000으로 한정
  • OS의 다크모드 활성화 여부를 기반으로 동작
  • 유저가 테마를 토글링할 수 있도록 좌측 상단에 해당 기능을 토글하는 체크박스를 생성.

🥕 CSS 주석 제거

style.css 내부 주석이 달린 코드가 있습니다. prefers-color-scheme는 운영체제에 따라 dark/white 중 어떤 모드를 사용하는지 탐지 할 수 있습니다.

style.css

@media (prefers-color-scheme: dark) {
  body {
    background-color: #000;
    color: white;
  }
}

🥕 운영체제 탐지

widnow.matchMedia()는 주어진 미디어 쿼리 문자열의 분석 결과를 나타내는 객체를 반환합니다. 이를 활용해서 prefers-color-scheme를 분석하여 사용하는 모드를 탐지할 수 있습니다.

그에 따라 html body에 dark/white 모드 속성을 추가합니다.

DarkMode.js

export const DarkMode = () => {
  var $theme = document.body.dataset.theme;
  if (!$theme) {
    $theme = window.matchMedia("(prefers-color-scheme: dark)").matches
      ? "dark"
      : "light";
    document.body.setAttribute("data-theme", $theme);
  }
}

다크모드에 대한 이해가 완료되었으니, 이후 파일을 수정합니다. 다크모드를 사용자가 선택하여 적용할 수 있도록 토글을 생성하여 App.js에 렌더링합니다. 토글에 대한 스타일과 data-theme에 대한 스타일은 다음을 확인해서 사용해주세요.

DarkMode.js

export default function DarkMode({ $app }) {
  var $theme = document.body.dataset.theme;
  if (!$theme) {
    $theme = window.matchMedia("(prefers-color-scheme: dark)").matches
      ? "dark"
      : "light";
    document.body.setAttribute("data-theme", $theme);
  }

  this.$target = document.createElement("label");
  this.$target.className = "DarkModeToggle";

  this.$checkbox = document.createElement("input");
  this.$checkbox.type = "checkbox";

  this.$toggle = document.createElement("span");
  this.$toggle.className = "slider round";

  this.$target.appendChild(this.$checkbox);
  this.$target.appendChild(this.$toggle);

  $app.appendChild(this.$target);

  this.$target.addEventListener("click", (e) => {
    const $themeMode = e.target.checked ? "dark" : "light";
    document.body.setAttribute("data-theme", $themeMode);
  });
}

style-toggle.css

.DarkModeToggle {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 26px;

  margin-bottom: 1em;
}

.DarkModeToggle input {
  opacity: 0;
  width: 0;
  height: 0;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: 0.4s;
  transition: 0.4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 18px;
  width: 18px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: 0.4s;
  transition: 0.4s;
}

input:checked + .slider {
  background-color: #2196f3;
}

input:checked + .slider:before {
  transform: translateX(18px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}

style.css

...

body[data-theme="dark"] {
  background-color: #000;
  color: white;
}

🐇 랜덤 고양이 배너 섹션

고양이 배너 섹션의 경우 이미지가 잘게 나누어저 전부 표현되거나, 이미지 중간 공백이 없거나, 이미지가 가운데로 표현되지 않는 경우가 많이 존재했습니다. 해당 불편함을 해소하기 위해 다음과 같이 스타일링했습니다.

.SlideShow {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 300px;
  margin: 1em auto;
}

.Slides {
  display: flex;
  flex-direction: row;
  align-items: center;
  overflow-x: hidden;
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0.125em;
}

.Slides > li {
  display: flex;
  list-style-type: none;
  align-items: center;
  width: 30%;
  height: 90%;
  padding: 0 0.55em;
}

.Slides > li > img {
  width: 200px;
  height: 210px;
  object-fit: cover;
}

.prev,
.next {
  cursor: pointer;
  text-align: center;
  font-weight: bold;
  font-size: 32px;
  width: 5%;
}

🐇 반응형 CSS 지원

디바이스 길이에 따라 검색결과 개수를 row당 column개수를 적절히 변경해야합니다.

style-media.css

@media (max-width: 992px) {
  .SearchResult {
    grid-template-columns: repeat(3, minmax(250px, 1fr));
  }
}
@media (max-width: 768px) {
  .SearchResult {
    grid-template-columns: repeat(2, minmax(250px, 1fr));
  }
  
}
@media (max-width: 576px) {
  .SearchResult {
    grid-template-columns: repeat(1, minmax(250px, 1fr));
  }
}

해당 기능을 검색 결과에만 적용하지 않고, 검색 창, 슬라이드쇼 등 적용시켜 커스텀해보았습니다. 다음 전체적인 반응형 css를 참고하여 활용해주세요.

style-media.css

@media (max-width: 992px) {
  .SearchRandom {
    width: 9%;
    font-size: 12px;
  }
  .SearchRandom > span {
    font-size: 1.25em;
  }
  .SearchResult {
    grid-template-columns: repeat(3, minmax(250px, 1fr));
  }
  .SearchError {
    font-size: 56px;
  }
  .Slides > li {
    padding: 0.495em;
  }
  .Slides > li > img {
    width: 155px;
    height: 165px;
  }
}
@media (max-width: 768px) {
  .SearchRandom {
    width: 9%;
    font-size: 8px;
  }
  .SearchRandom > span {
    font-size: 1em;
  }
  .SearchResult {
    grid-template-columns: repeat(2, minmax(250px, 1fr));
  }
  .SearchError {
    font-size: 42px;
  }
  .ImageInfo .content-wrapper {
    width: 100%;
  }
  .Slides > li {
    padding: 0.3em;
  }
  .Slides > li > img {
    width: 122.5px;
    height: 130px;
  }
}
@media (max-width: 576px) {
  .SearchRandom {
    width: 7%;
    font-size: 6px;
  }
  .SearchRandom > span {
    font-size: 0.75em;
  }
  .SearchResult {
    grid-template-columns: repeat(1, minmax(250px, 1fr));
  }
  .SearchError {
    font-size: 24px;
  }
  .Slides > li {
    padding: 0.2em;
  }
  .Slides > li > img {
    width: 90px;
    height: 95px;
  }
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: #000;
    color: white;
  }
}
profile
기억은 기록을 이길수 없다

0개의 댓글