Как открыть якорную ссылку с отступом сверху?
Сверху сайта шапка с меню со свойствами "height: 80px", "background: #......" и "position: fixed".
В середине контентная часть со свойством "margin: 80px 0px 0px 0px" и заголовками с уникальными идентификаторами "id="...".
В меню шапки ссылки типа "href="#..." на заголовки в контентной части.
При активации ссылки фокус переходит к заголовку, но он отображается с самого верха страницы, под фоном шапки.
Я конечно догадываюсь, что сделал супер криво, но тем не менее, есть ли вариант перейти на ссылку со сдвигом фокуса от верха страницы в 80px?
* {
box-sizing: border-box;
}
a {
text-decoration: none;
}
ul, li {
padding: 0;
margin: 0;
}
hr {
padding: 0;
margin: 0;
}
body {
padding: 0;
margin: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 16px;
background: #E7EBF0;
color: #003366;
}
.wrapper {
min-height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
}
.container {
width: 1170px;
margin: 0px auto;
background: #E7EBF0;
}
.header {
position: fixed;
width: 100%;
}
.header__row {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #003366;
}
.header__logo {
}
.header__image {
height: 80px;
width: 320px;
}
.header__catalog {
}
.header__nav {
display: flex;
flex-direction: row;
}
.header__nav a {
letter-spacing: 0.10em;
height: 31px;
color: #003366;
text-transform: uppercase;
font-weight: normal;
background-color: #E7EBF0;
padding: 5px;
margin: auto 5px;
}
.header__nav a:hover {
color: #663366;
background-color: #B1BDCD;
transition-duration: 0.5s;
}
.header__nav a:focus {
color: #663366;
background-color: #B1BDCD;
transition-duration: 0.5s;
}
.header__nav a:active {
color: #660F57;
background-color: #B1BDCD;
transition-duration: 0.5s;
}
.header__contacts {
}
.content {
width: 100%;
flex: 1 1 auto;
margin: 82px auto 20px;
}
.content__row {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content__about {
display: flex;
flex-direction: column;
margin: 20px;
padding: 10px;
border: 1px solid #003366;
}
.content__about-head {
display: flex;
flex-direction: row;
margin: 0px auto 0px 0px;
}
.content__triangle-top-left {
width: 0;
height: 0;
border-top: 50px solid #003366;
border-right: 50px solid transparent;
}
.content__about-title {
font-size: 20px;
text-transform: uppercase;
margin: auto 0px;
}
.content__about-subtitle {
margin: 5px;
text-indent: 20px;
}
.content__about-end {
display: flex;
flex-direction: row;
margin: 0px 0px 0px auto;
}
.content__triangle-bot-right {
width: 0;
height: 0;
border-bottom: 50px solid #003366;
border-left: 50px solid transparent;
margin-left: auto;
}
.content__about-second-title {
font-size: 12px;
font-style: italic;
margin: auto;
}
.footer__row {
display: flex;
justify-content: center;
align-items: center;
border-top: 2px solid #003366;
height: 40px;
}
<!DOCTYPE html>
<html>
<head>
<title>...</title>
<link href="css/style.css" type="text/css" rel="stylesheet" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
</head>
<body>
<div class="wrapper">
<header class="header">
<div class="container">
<div class="header__row">
<a class="header__logo" href="../index.html">
<img class="header__image" src="..." alt="...">
</a>
<nav class="header__nav">
<a class="button-about" href="#about">Ссылка</a>
<a class="button-catalog" href="#catalog">...</a>
<a class="button-services" href="#services">...</a>
<a class="button-contacts" href="#contacts">...</a>
</nav>
<ul type="none" class="header__contacts">
<li>...</li>
<li>...</li>
</ul>
</div>
</div>
</header>
<content class="content">
<div class="container">
<div class="content__row">
<div class="content__about">
<div class="content__about-head">
<div class="content__triangle-top-left">
</div>
<p class="content__about-title">
<a id="about">
ID<br />
<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
1<br />
</a>
</p>
</div>
<p class="content__about-subtitle">
</p>
<div class="content__about-end">
<p class="content__about-second-title">
...<br />
...<br />
...<br />
</p>
<div class="content__triangle-bot-right">
</div>
</div>
</div>
</div>
</div>
</content>
<footer class="footer">
<div class="container">
<div class="footer__row">
<a class="footer__text">...</a>
</div>
</div>
</footer>
</div>
</body>
</html>
Ответы (4 шт):
Что бы сохранить возможность прямого обращения по якорным ссылкам извне и при этом иметь возможность скроллить с их помощью к нужным частям документа можно сделать так:
const handleClick = event => {
event.preventDefault()
const headerOffset = 60 // полная высота header'a
const contentAnchors = document.querySelectorAll(".anchor-hash-content")
const href = event.target.getAttribute("href")
const elementToScroll = Array.from(contentAnchors).filter(item =>
item.getAttribute("href") === href)
const elementPosition = elementToScroll[0].offsetTop
window.scrollTo({
top: elementPosition - headerOffset,
behavior: "smooth"
})
}
document.querySelectorAll(".anchor-hash-header").forEach(item =>
item.addEventListener("click", handleClick))
// игнорирует клики по заголовкам, здесь только для примера
document.querySelectorAll(".anchor-hash-content").forEach(item =>
item.addEventListener("click", event => event.preventDefault()))
body {
height: 1000px;
}
.menu {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
background-color: red;
padding: 20px;
}
.menu > span {
margin-right: auto;
}
.menu > a {
padding: 0 10px;
}
.anchor-hash-content {
display: block;
margin: 100px 0;
}
<div class="menu"><span>Меню</span>
<a class="anchor-hash-header" href="aaa">Anchor 1</a>
<a class="anchor-hash-header" href="bbb">Anchor 2</a>
</div>
<a class="anchor-hash-content" href="aaa">Content 1</a>
<a class="anchor-hash-content" href="bbb">Content 2</a>
Для того что бы сдвигать заголовок ниже уровня header'a при открытии, как вариант, можно проверять URL при загрузке, и в случае якорей сдвигать заголовок в нужное (видимое) положение:
const scrollToHash = urlHash => {
const headerOffset = 60 // полная высота header'a
const contentAnchors = document.querySelectorAll(".anchor-hash-content")
const elementToScroll = Array.from(contentAnchors).filter(item =>
item.getAttribute("href") === urlHash)
const elementPosition = elementToScroll[0].offsetTop
window.scrollTo({ top: elementPosition - headerOffset })
}
(() => {
const url = new URL(window.location)
const urlHash = url.hash
if (urlHash) {
scrollToHash(urlHash.substr(1)) // убираем символ #
}
})()
Сработало вот что:
#about {
padding-top: 80px;
margin-top: -80px;
}
<div class="block">
<div class="anchor" id="scroll"></div>
</div>
.block {
position: relative;
}
.anchor {
position: absolute;
visibility: hidden;
top: -80px;
left: 0;
}
Вариант с использованием https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin-top
html {
scroll-behavior: smooth;
}
body {
margin: 0;
}
.menu {
position: sticky;
top: 0;
left: 0;
right: 0;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
background-color: red;
padding: 20px;
box-sizing: border-box;
}
.menu>span {
margin-right: auto;
}
.menu>a {
padding: 0 10px;
}
.section {
display: block;
min-height: 100vh;
scroll-margin-top: calc(40px + 10px);
}
<nav class="menu">
<span>Меню</span>
<a href="#section1">Anchor 1</a>
<a href="#section2">Anchor 2</a>
</nav>
<section class="section" id="section1">Content 1</section>
<section class="section" id="section2">Content 2</section>