Html 使用 Transition/CSS3 滚动到锚点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25020582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scrolling to an Anchor using Transition/CSS3
提问by user18490
I have a series of links which are using an anchor mechanism:
我有一系列使用锚点机制的链接:
<div class="header">
<p class="menu"><a href="#S1">Section1</a></p>
<p class="menu"><a href="#S2">Section2</a></p>
...
</div>
<div style="width: 100%;">
<a name="S1" class="test"> </a>
<div class="curtain">
Lots of text
</div>
<a name="S2" class="test"> </a>
<div class="curtain">
lots of text
</div>
...
</div>
I am using the following CSS:
我正在使用以下 CSS:
.test
{
position:relative;
margin: 0;
padding: 0;
float: left;
display: inline-block;
margin-top: -100px; /* whatever offset this needs to be */
}
It's working fine. But of course, it's jumping from one section to the next when we click on the link. So I'd like to have a smooth transition, using a scroll of some sort to the start of selected section.
它工作正常。但当然,当我们单击链接时,它会从一个部分跳到下一个部分。所以我想有一个平滑的过渡,使用某种滚动到所选部分的开头。
I think I read on Stackoverflow that this is not possible (yet) with CSS3 but I'd like a confirmation and also I'd like to know what 'could' be the solution. I am happy to use JS but I can't use jQuery. I tried to use an on click function on the link, retrieve the "vertical position" of the div that needs to be displayed but I was unsuccessful. I am still learning JS and don't know it well enough to come up with a solution of my own.
我想我在 Stackoverflow 上读到,这在 CSS3 中是不可能的(还),但我想确认一下,而且我想知道什么是“可能”的解决方案。我很高兴使用 JS,但我不能使用 jQuery。我试图在链接上使用点击功能,检索需要显示的 div 的“垂直位置”,但我没有成功。我还在学习 JS,对它的了解还不够充分,无法提出自己的解决方案。
Any help/ideas would be greatly appreciated.
任何帮助/想法将不胜感激。
采纳答案by user18490
While some of the answers were very useful and informative, I thought I would write down the answer I came up with. The answer from Alex was very good, it is however limited in the sense that the height of the div needs to be hard coded in the CSS.
虽然有些答案非常有用且内容丰富,但我想我会写下我想出的答案。Alex 的回答非常好,但是在 div 的高度需要在 CSS 中进行硬编码的意义上是有限的。
So the solution I came up with uses JS (no jQuery) and is actually a stripped down version (almost to the minimum) of over solutions to solve similar problems I found on Statckoverflow:
所以我想出的解决方案使用 JS(没有 jQuery)并且实际上是一个精简版本(几乎到最低限度)的过度解决方案来解决我在 Statckoverflow 上发现的类似问题:
HTML
HTML
<div class="header">
<p class="menu"><a href="#S1" onclick="test('S1'); return false;">S1</a></p>
<p class="menu"><a href="#S2" onclick="test('S2'); return false;">S2</a></p>
<p class="menu"><a href="#S3" onclick="test('S3'); return false;">S3</a></p>
<p class="menu"><a href="#S4" onclick="test('S4'); return false;">S3</a></p>
</div>
<div style="width: 100%;">
<div id="S1" class="curtain">
blabla
</div>
<div id="S2" class="curtain">
blabla
</div>
<div id="S3" class="curtain">
blabla
</div>
<div id="S4" class="curtain">
blabla
</div>
</div>
NOTE THE "RETURN FALSE;" in the on click call.This is important if you want to avoid having your browser jumping to the link itself (and let the effect being managed by your JS).
注意“返回错误”;在点击通话中。如果您想避免让浏览器跳转到链接本身(并让效果由您的 JS 管理),这很重要。
JS code:
JS代码:
<script>
function scrollTo(to, duration) {
if (document.body.scrollTop == to) return;
var diff = to - document.body.scrollTop;
var scrollStep = Math.PI / (duration / 10);
var count = 0, currPos;
start = element.scrollTop;
scrollInterval = setInterval(function(){
if (document.body.scrollTop != to) {
count = count + 1;
currPos = start + diff * (0.5 - 0.5 * Math.cos(count * scrollStep));
document.body.scrollTop = currPos;
}
else { clearInterval(scrollInterval); }
},10);
}
function test(elID)
{
var dest = document.getElementById(elID);
scrollTo(dest.offsetTop, 500);
}
</script>
It's incredibly simple. It finds the vertical position of the div in the document using its unique ID (in the function test). Then it calls the scrollTo function passing the starting position (document.body.scrollTop) and the destination position (dest.offsetTop). It performs the transition using some sort of ease-inout curve.
这非常简单。它使用其唯一 ID(在函数测试中)查找文档中 div 的垂直位置。然后它调用 scrollTo 函数传递起始位置 (document.body.scrollTop) 和目标位置 (dest.offsetTop)。它使用某种缓入曲线执行过渡。
Thanks everyone for your help.
感谢大家的帮助。
Knowing a bit of coding can help you avoiding (sometimes heavy) libraries, and giving you (the programmer) more control.
了解一点编码可以帮助您避免(有时是繁重的)库,并为您(程序员)提供更多控制权。
回答by vsync
Using the scroll-behavior
CSS property:
使用scroll-behavior
CSS 属性:
(which is supportedin modern browsers but not Edge):
a {
display: inline-block;
padding: 5px 7%;
text-decoration: none;
}
nav, section {
display: block;
margin: 0 auto;
text-align: center;
}
nav {
width: 350px;
padding: 5px;
}
section {
width: 350px;
height: 130px;
overflow-y: scroll;
border: 1px solid black;
font-size: 0;
scroll-behavior: smooth; /* <----- THE SECRET ---- */
}
section div{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 8vw;
}
<nav>
? <a href="#page-1">1</a>
? <a href="#page-2">2</a>
? <a href="#page-3">3</a>
</nav>
<section>
? <div id="page-1">1</div>
? <div id="page-2">2</div>
? <div id="page-3">3</div>
</section>
回答by Alex Podworny
You can find the answer to your question on the following page:
您可以在以下页面找到问题的答案:
https://stackoverflow.com/a/17633941/2359161
https://stackoverflow.com/a/17633941/2359161
Here is the JSFiddle that was given:
这是给出的 JSFiddle:
Note the scrolling section at the end of the CSS, specifically:
请注意 CSS 末尾的滚动部分,特别是:
/*
*Styling
*/
html,body {
width: 100%;
height: 100%;
position: relative;
}
body {
overflow: hidden;
}
header {
background: #fff;
position: fixed;
left: 0; top: 0;
width:100%;
height: 3.5rem;
z-index: 10;
}
nav {
width: 100%;
padding-top: 0.5rem;
}
nav ul {
list-style: none;
width: inherit;
margin: 0;
}
ul li:nth-child( 3n + 1), #main .panel:nth-child( 3n + 1) {
background: rgb( 0, 180, 255 );
}
ul li:nth-child( 3n + 2), #main .panel:nth-child( 3n + 2) {
background: rgb( 255, 65, 180 );
}
ul li:nth-child( 3n + 3), #main .panel:nth-child( 3n + 3) {
background: rgb( 0, 255, 180 );
}
ul li {
display: inline-block;
margin: 0 8px;
margin: 0 0.5rem;
padding: 5px 8px;
padding: 0.3rem 0.5rem;
border-radius: 2px;
line-height: 1.5;
}
ul li a {
color: #fff;
text-decoration: none;
}
.panel {
width: 100%;
height: 500px;
z-index:0;
-webkit-transform: translateZ( 0 );
transform: translateZ( 0 );
-webkit-transition: -webkit-transform 0.6s ease-in-out;
transition: transform 0.6s ease-in-out;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.panel h1 {
font-family: sans-serif;
font-size: 64px;
font-size: 4rem;
color: #fff;
position:relative;
line-height: 200px;
top: 33%;
text-align: center;
margin: 0;
}
/*
*Scrolling
*/
a[ id= "servicios" ]:target ~ #main article.panel {
-webkit-transform: translateY( 0px);
transform: translateY( 0px );
}
a[ id= "galeria" ]:target ~ #main article.panel {
-webkit-transform: translateY( -500px );
transform: translateY( -500px );
}
a[ id= "contacto" ]:target ~ #main article.panel {
-webkit-transform: translateY( -1000px );
transform: translateY( -1000px );
}
<a id="servicios"></a>
<a id="galeria"></a>
<a id="contacto"></a>
<header class="nav">
<nav>
<ul>
<li><a href="#servicios"> Servicios </a> </li>
<li><a href="#galeria"> Galeria </a> </li>
<li><a href="#contacto">Contacta nos </a> </li>
</ul>
</nav>
</header>
<section id="main">
<article class="panel" id="servicios">
<h1> Nuestros Servicios</h1>
</article>
<article class="panel" id="galeria">
<h1> Mustra de nuestro trabajos</h1>
</article>
<article class="panel" id="contacto">
<h1> Pongamonos en contacto</h1>
</article>
</section>
回答by Reign.85
Only mozilla implements a simple property in css : http://caniuse.com/#search=scroll-behavior
只有 mozilla 在 css 中实现了一个简单的属性:http: //caniuse.com/#search=scroll-behavior
you will have to use JS at least.
你至少必须使用JS。
I personally use this because its easy to use (I use JQ but you can adapt it I guess):
我个人使用它是因为它易于使用(我使用 JQ,但我猜你可以调整它):
/*Scroll transition to anchor*/
$("a.toscroll").on('click',function(e) {
var url = e.target.href;
var hash = url.substring(url.indexOf("#")+1);
$('html, body').animate({
scrollTop: $('#'+hash).offset().top
}, 500);
return false;
});
just add class toscroll to your a tag
只需将 class toscroll 添加到您的标签中
回答by Kalin Krastev
If anybody is just like me willing to use jQuery, but still found himself looking to this question then this may help you guys:
如果有人像我一样愿意使用 jQuery,但仍然发现自己在寻找这个问题,那么这可能对你们有所帮助:
https://html-online.com/articles/animated-scroll-anchorid-function-jquery/
https://html-online.com/articles/animated-scroll-anchorid-function-jquery/
$(document).ready(function () {
$("a.scrollLink").click(function (event) {
event.preventDefault();
$("html, body").animate({ scrollTop: $($(this).attr("href")).offset().top }, 500);
});
});
<a href="#anchor1" class="scrollLink">Scroll to anchor 1</a>
<a href="#anchor2" class="scrollLink">Scroll to anchor 2</a>
<p id="anchor1"><strong>Anchor 1</strong> - Lorem ipsum dolor sit amet, nonumes voluptatum mel ea.</p>
<p id="anchor2"><strong>Anchor 2</strong> - Ex ignota epicurei quo, his ex doctus delenit fabellas.</p>
回答by user3405291
I implemented the answersuggested by @user18490 but ran into two problems:
我实现了@user18490 建议的答案,但遇到了两个问题:
- First bouncingwhen user clicks on several tabs/links multiple times in short succession
- Second, the
undefined
errormentioned by @krivar
- 当用户连续多次点击多个选项卡/链接时,首次弹跳
- 二、@krivar 提到的
undefined
错误
I developed the following class to get around the mentioned problems, and it works fine:
我开发了以下课程来解决上述问题,并且效果很好:
export class SScroll{
constructor(){
this.delay=501 //ms
this.duration=500 //ms
this.lastClick=0
}
lastClick
delay
duration
scrollTo=(destID)=>{
/* To prevent "bounce" */
/* https://stackoverflow.com/a/28610565/3405291 */
if(this.lastClick>=(Date.now()-this.delay)){return}
this.lastClick=Date.now()
const dest=document.getElementById(destID)
const to=dest.offsetTop
if(document.body.scrollTop==to){return}
const diff=to-document.body.scrollTop
const scrollStep=Math.PI / (this.duration/10)
let count=0
let currPos
const start=window.pageYOffset
const scrollInterval=setInterval(()=>{
if(document.body.scrollTop!=to){
count++
currPos=start+diff*(.5-.5*Math.cos(count*scrollStep))
document.body.scrollTop=currPos
}else{clearInterval(scrollInterval)}
},10)
}
}
UPDATE
更新
There is a problem with Firefox as mentioned here. Therefore, to make it work on Firefox, I implemented the following code. It works fine on Chromium-based browsers and also Firefox.
此处提到的 Firefox 存在问题。因此,为了使其在 Firefox 上工作,我实现了以下代码。它适用于基于 Chromium 的浏览器和 Firefox。
export class SScroll{
constructor(){
this.delay=501 //ms
this.duration=500 //ms
this.lastClick=0
}
lastClick
delay
duration
scrollTo=(destID)=>{
/* To prevent "bounce" */
/* https://stackoverflow.com/a/28610565/3405291 */
if(this.lastClick>=(Date.now()-this.delay)){return}
this.lastClick=Date.now()
const dest=document.getElementById(destID)
const to=dest.offsetTop
if((document.body.scrollTop || document.documentElement.scrollTop || 0)==to){return}
const diff=to-(document.body.scrollTop || document.documentElement.scrollTop || 0)
const scrollStep=Math.PI / (this.duration/10)
let count=0
let currPos
const start=window.pageYOffset
const scrollInterval=setInterval(()=>{
if((document.body.scrollTop || document.documentElement.scrollTop || 0)!=to){
count++
currPos=start+diff*(.5-.5*Math.cos(count*scrollStep))
/* https://stackoverflow.com/q/28633221/3405291 */
/* To support both Chromium-based and Firefox */
document.body.scrollTop=currPos
document.documentElement.scrollTop=currPos
}else{clearInterval(scrollInterval)}
},10)
}
}
回答by Sir Celsius
I guess it might be possible to set some kind of hardcore transition to the top
style of a #container
div
to move your entire page in the desired direction when clicking your anchor. Something like adding a class that has top:-2000px
.
我想可能可以设置某种硬核过渡到 a 的top
样式,#container
div
以便在单击锚点时将整个页面向所需方向移动。就像添加一个具有top:-2000px
.
I did use JQuery because I'm to lazy too use native JS, but it is not necessary for what I did.
我确实使用了 JQuery,因为我也懒得使用原生 JS,但这对我所做的没有必要。
This is probably not the best possible solution because the top content just moves towards the top and you can't get it back easily, you should definitely use JQuery if you really need that scroll animation.
这可能不是最好的解决方案,因为顶部内容只是移向顶部并且您无法轻松恢复它,如果您确实需要滚动动画,则绝对应该使用 JQuery。
回答by user7915231
Here is a pure css solution using viewport units and variables that automatically scales to the device (and works on window resize). I added the following to Alex's solution:
这是一个纯 css 解决方案,使用视口单位和自动缩放到设备的变量(并适用于窗口大小调整)。我在 Alex 的解决方案中添加了以下内容:
html,body {
width: 100%;
height: 100%;
position: fixed;/* prevents scrolling */
--innerheight: 100vh;/* variable 100% of viewport height */
}
body {
overflow: hidden; /* prevents scrolling */
}
.panel {
width: 100%;
height: var(--innerheight); /* viewport height */
a[ id= "galeria" ]:target ~ #main article.panel {
-webkit-transform: translateY( calc(-1*var(--innerheight)) );
transform: translateY( calc(-1*var(--innerheight)) );
}
a[ id= "contacto" ]:target ~ #main article.panel {
-webkit-transform: translateY( calc(-2*var(--innerheight)) );
transform: translateY( calc(-2*var(--innerheight)) );