// <h1 class="heading-primary">
// A healthy meal delivered to your door, every single day
// </h1>
const myName = "Jonas Schmedtmann";
const h1 = document.querySelector(".heading-primary");
console.log(myName);
console.log(h1);
// html 조작
h1.textContent = myName;
// css 조작
// h1.style.backgroundColor = "red";
// h1.style.padding = "5rem";
h1.addEventListener("click", function () {
h1.style.backgroundColor = "red";
h1.style.padding = "5rem";
});
///////////////////////////////////////////////////////////
// Set current year
// <p class="copyright">
// Copyright © <span class="year">2027</span> by Omnifood, Inc. All rights reserved.
// </p>
const yearElement = document.querySelector(".year");
const currentYear = new Date().getFullYear() + " ";
yearElement.textContent = currentYear;
///////////////////////////////////////////////////////////
// Make mobile navigation work
// <button class="btn-mobile-nav">
// <ion-icon class="icon-mobile-nav" name="menu-outline"></ion-icon>
// <ion-icon class="icon-mobile-nav" name="close-outline"></ion-icon>
// </button>
const btnNavEl = document.querySelector(".btn-mobile-nav");
const headerEl = document.querySelector(".header"); // header가 btn-mobile-nav의 parent
btnNavEl.addEventListener("click", function () {
headerEl.classList.toggle("nav-open");
});
/* MOBILE NAVIGATION */
.btn-mobile-nav {
display: block;
z-index: 1000; /* 메뉴 펼치는 버튼이 맨 위에 있도록 */
}
href="#"
로 페이지 상단으로 이동한다.id
를 부여한다.<section class="section-cta" id="cta">
...
</secition>
href="#"
를 href="#cta"
로 수정한다.<main>
<section class="section-hero">
<div class="hero">
<div class="hero-text-box">
<a href="#cta" class="btn btn--full margin-right-sm">Start eating well</a>
..
/#cta
가 된다.<section class="section-how" id="how">
...
</secition>
<section class="section-meals" id="meals">
...
</section>
<section class="section-testimonials" id="testimonials">
...
</secition>
<section class="section-pricing" id="pricing">
...
</section>
<nav class="main-nav">
<ul class="main-nav-list">
<li><a class="main-nav-link" href="#how">How it works</a></li>
<li><a class="main-nav-link" href="#meals">Meals</a></li>
<li><a class="main-nav-link" href="#testimonials">Testimonials</a></li>
<li><a class="main-nav-link" href="#pricing">Pricing</a></li>
<li><a class="main-nav-link nav-cta" href="#cta">Try for free</a></li>
</ul>
</nav>
<a href="#how" class="btn btn--outline">Learn more ↓</a>
html
에 scroll-behavior: smooth
속성을 준다. (강의 당시 사파리 브라우저와 모든 iOS에는 적용되지 않았으나 현재는 잘 ) /* general.css */
html {
...
scroll-behavior: smooth;
}
const allLinks = document.querySelectorAll("a:link");
console.log(allLinks);
forEach()
를 사용한다.const allLinks = document.querySelectorAll("a:link");
// console.log(allLinks);
allLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
console.log(e);
});
});
.preventDefault()
로 기본 동작을 끄고 href
에 설정된 값을 읽어온다.const allLinks = document.querySelectorAll("a:link");
// console.log(allLinks);
allLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
e.preventDefault();
// href에 설정된 값 읽기
const href = link.getAttribute("href");
// console.log(href);
// Scroll back to top
if (href == "#")
window.scrollTo({
top: 0, // top에서 0px 떨어진 위치로 이동
behavior: "smooth",
});
});
});
강의 당시 scrollTo의 속성 역시 사파리에서 지원하지 않았기 때문에 아래처럼 html
에 polyfill을 넣어야 했다.
<script defer src="https://unpkg.com/smoothscroll-polyfill@0.4.4/dist/smoothscroll.min.js"></script>
현재의 compatibility
scrollTo 대신 ScrollIntoView 사용하는 방법
const allLinks = document.querySelectorAll("a:link");
// console.log(allLinks);
allLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
e.preventDefault();
// href에 설정된 값 읽기
const href = link.getAttribute("href");
// console.log(href);
// Scroll back to top
if (href == "#")
window.scrollTo({
top: 0, // top에서 0px 떨어진 위치로 이동
behavior: "smooth",
});
if (href !== "#" && href.startsWith("#")) {
// console.log(href);
const sectionEl = document.querySelector(href);
console.log(sectionEl);
sectionEl.scrollIntoView({ behavior: "smooth" });
}
});
});
///////////////////////////////////////////////////////////
// Smooth scrolling animation
const allLinks = document.querySelectorAll("a:link");
// console.log(allLinks);
allLinks.forEach(function (link) {
link.addEventListener("click", function (e) {
e.preventDefault();
// href에 설정된 값 읽기
const href = link.getAttribute("href");
// console.log(href);
// Scroll back to top
if (href == "#")
window.scrollTo({
top: 0, // top에서 0px 떨어진 위치로 이동
behavior: "smooth",
});
// Scroll to other links
if (href !== "#" && href.startsWith("#")) {
// console.log(href);
const sectionEl = document.querySelector(href);
console.log(sectionEl);
sectionEl.scrollIntoView({ behavior: "smooth" });
}
// Close mobile navigation
if (link.classList.contains("main-nav-link"))
headerEl.classList.toggle("nav-open");
});
});
<header class="header sticky">
...
</header>
.sticky {
position: fixed;
top: 0;
bottom: 0;
width: 100%;
height: 8rem;
padding-top: 0;
padding-bottom: 0;
background-color: rgba(255, 255, 255, 0.97);
z-index: 9999;
box-shadow: 0 1.2rem 3.2rem rgba(0, 0, 0, 0.03);
}
///////////////////////////////////////////////////////////
// Sticky navigation
const sectionHeroEl = document.querySelector(".section-hero");
const observer = new IntersectionObserver(
function (entries) {
const ent = entries[0];
// console.log(ent);
// intersectionRatio, isIntersecting 주목
if (!ent.isIntersecting) {
// document.querySelector(".header").classList.add("sticky");
document.body.classList.add("sticky");
}
if (ent.isIntersecting) {
document.body.classList.remove("sticky");
}
},
{
// In the viewport
root: null,
threshold: 0,
// 섹션이 뷰포트를 완전히 벗어나자마자 이벤트가 발생하게 한 것.
rootMargin: "-80px",
}
);
observer.observe(sectionHeroEl);
// 관찰하고자 하는 섹션: hero.
// 위 섹션이 뷰포트에서 나오자마자 네비게이션이 sticky하길 원한다.
/* STICKY NAVIGATION */
.sticky .header {
position: fixed;
top: 0;
bottom: 0;
width: 100%;
height: 8rem;
padding-top: 0;
padding-bottom: 0;
background-color: rgba(255, 255, 255, 0.97);
z-index: 9999;
box-shadow: 0 1.2rem 3.2rem rgba(0, 0, 0, 0.03);
}
.sticky .section-hero {
margin-top: 9.6rem;
}
10년도 더 전에는 중요한 주제였다.
browser support란 웹 브라우저마다 다른 CSS 속성을 지원한다는 뜻이다.
우리가 만든 웹사이트가 브라우저마다 다르게 보였다.
아래 사이트에서 다양한 브라우저 지원을 볼 수 있다.
Can I use... Support tables for HTML5, CSS3, etc
backdrop-filter
에 대해 알아보면 몇몇 브라우저에서 supported with prefix: -webkit-
을 볼 수 있다..main-nav {
background-color: rgba(255, 255, 255, 0.5);
...
}
.main-nav {
background-color: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(10px);
...
}
.main-nav {
background-color: rgba(255, 255, 255, 0.5);
-webkit-backdrop-filter: blur(10px);
...
}
///////////////////////////////////////////////////////////
// Fixing flexbox gap property missing in some Safari versions
function checkFlexGap() {
var flex = document.createElement("div");
flex.style.display = "flex";
flex.style.flexDirection = "column";
flex.style.rowGap = "1px";
flex.appendChild(document.createElement("div"));
flex.appendChild(document.createElement("div"));
document.body.appendChild(flex);
var isSupported = flex.scrollHeight === 1;
flex.parentNode.removeChild(flex);
console.log(isSupported);
if (!isSupported) document.body.classList.add("no-flexbox-gap");
}
checkFlexGap();
<meta
name="decription"
content="Omnifood is an AI-powered food subscription that will make you eat healthy again, 365 per year. It's tailored to your personal tastes and nutritional needs."
/>
<link *rel*="icon" *href*="img/favicon.png" />
<link *rel*="apple-touch-icon" *href*="img/apple-touch-icon.png" />
<link *rel*="manifest" *href*="manifest.webmanifest" />
// 일종의 확장 파일.
// 기본적으로 다른 파비콘을 인식하기 위해 Android를 위해 사용된다.
// index.html과 같은 위치 manifest.webmanifest 파일을 만들고 아래처럼 작성한다.
{
"icons": [
{ "src": "img/favicon-192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "img/favicon-512.png", "type": "image/png", "sizes": "512x512" }
]
}
크기를 조절해준다. (강의에서는 렌더링된 크기의 가로가 500px 후반대로, 고유 크기를 600px 기준 2배인 1200px로 해주었다.)
<img
src="img/hero.webp"
class="hero-img"
alt="Woman enjoying food, meals in storage container, and food bowls on a table"
/>
<picture>
<source srcset="img/hero.webp" type="image/webp"/>
<source srcset="img/hero-min.png" type="image/png"/>
<img
src="img/hero.webp"
class="hero-img"
alt="Woman enjoying food, meals in storage container, and food bowls on a table"
/>
</picture>
→ 이제 브라우저가 두 어미지 중 디스플레이 할 수 있는 것 중 좋은 것을 선택한다.<form name="contact" netlify>
<p>
<label>Name <input type="text" name="name" /></label>
</p>
<p>
<label>Email <input type="email" name="email" /></label>
</p>
<p>
<button type="submit">Send</button>
</p>
</form>
코드에서 아래와 같이 변경해주고 다시 배포해야 한다.
<form class="cta-form" name="sign-up" netlify>
<div>
<label for="full-name">Full Name</label>
<input
id="full-name"
type="text"
placeholder="John Smith"
name="full-name"
required
/>
</div>
<div>
<label for="email">Email address</label>
<input
id="email"
type="email"
placeholder="me@example.com"
name="email"
required
/>
</div>
<div>
<label for="select-where">Where did you hear from us?</label>
<select id="select-where" name="select-where" required>
<option value="">Please choose one option:</option>
<option value="friends">Friends and family</option>
<option value="youtube">YouTube video</option>
<option value="podcast">Podcast</option>
<option value="ad">Facebook ad</option>
<option value="others">Others</option>
</select>
</div>
<button class="btn btn--form">Sign up now</button>
<!-- <input type="checkbox" />
<input type="number" /> -->
</form>
- netlify에서 아래와 같이 자동으로 `method="post"`를 추가해준 것을 알 수 있다.