Przewijanie do zakotwiczenia za pomocą przejścia / CSS3

Mam serię linków, które używają mechanizmu kotwicy:

<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">&nbsp;</a>
<div class="curtain">
Lots of text
</div>

<a name="S2" class="test">&nbsp;</a>
<div class="curtain">
lots of text
</div>
...
</div>

Używam następującego CSS:

.test
{
    position:relative; 
    margin: 0; 
    padding: 0; 
    float: left;
    display: inline-block;
    margin-top: -100px; /* whatever offset this needs to be */
}
Działa dobrze. Ale oczywiście przeskakuje z jednej sekcji do drugiej, gdy klikamy na link. Więc chciałbym mieć płynne przejście, używając jakiegoś zwoju na początek wybranego sekcja.

Myślę, że czytałem na Stackoverflow, że to nie jest możliwe (jeszcze) z CSS3, ale chciałbym potwierdzenie i również chciałbym wiedzieć, co "może" być rozwiązanie. Cieszę się, że mogę używać JS, ale nie mogę używać jQuery. Próbowałem użyć funkcji kliknięcia na link, pobrać "pozycję pionową" div, który musi być wyświetlany, ale nie powiodło mi się. Wciąż uczę się JS i nie znam go na tyle dobrze, aby wymyślić własne rozwiązanie.

Każda pomoc / pomysły będą bardzo mile widziane.

 32
Author: user18490, 2014-07-29

8 answers

Odpowiedź na swoje pytanie znajdziesz na następującej stronie:

Https://stackoverflow.com/a/17633941/2359161

Oto jsfiddle, który został podany:

Http://jsfiddle.net/YYPKM/3/

Zwróć uwagę na sekcję przewijania na końcu CSS, a konkretnie:

/*
 *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>
 26
Author: Alex Podworny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-10 18:38:57

Chociaż niektóre odpowiedzi były bardzo przydatne i pouczające, pomyślałem, że napiszę odpowiedź, którą wymyśliłem. Odpowiedź Alexa była bardzo dobra, jest jednak ograniczona w tym sensie, że wysokość div musi być mocno zakodowana w CSS.

Więc rozwiązanie, które wymyśliłem, używa JS (bez jQuery) i jest w rzeczywistości okrojoną wersją (prawie do minimum) over solutions do rozwiązania podobnych problemów, które znalazłem na Statckoverflow:

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>

Uwaga "RETURN FALSE;" w wywołaniu on click. jest to ważne, jeśli chcesz uniknąć przeskakiwania przeglądarki do samego linku (i pozwolić, aby efekt był zarządzany przez twój JS).

Kod 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>
To niezwykle proste. Znajduje pionową pozycję div w dokumencie za pomocą jego unikalnego identyfikatora (w teście funkcji). Następnie wywołuje funkcję scrollTo przekazującą pozycję początkową (document.ciało.scrollTop) i pozycji docelowej (dest.offsetTop). Wykonuje Przejście za pomocą krzywej łatwości wejścia. Dziękuję wszystkim za pomoc.

Znajomość trochę kodowania może pomóc ci uniknąć (czasami ciężkich) bibliotek i dać ci (programiście) większą kontrolę.

 17
Author: user18490,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-22 03:57:39

Za pomocą scroll-behavior właściwość CSS:

(która jest obsługiwana w nowoczesnych przeglądarkach, ale nie 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>
 11
Author: vsync,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-15 08:52:21

Tylko mozzila implementuje prostą właściwość w css : http://caniuse.com/#search=scroll-behavior

Będziesz musiał użyć JS przynajmniej.

Używam tego, ponieważ jest łatwy w użyciu (użyj JQ, ale możesz go chyba dostosować):

/*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;
});

Po prostu dodaj klasę toscroll do twojego tagu a

 4
Author: Reign.85,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-27 09:08:25

Jeśli ktoś jest tak jak ja chętny do korzystania z jQuery, ale i tak znalazł się na tym pytaniu to może wam to pomóc:

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>
 2
Author: Kalin Krastev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-30 09:40:23

Chyba da się ustawić jakieś hardcore ' owe przejście na styl top#container div aby przesunąć całą stronę w żądanym kierunku po kliknięciu kotwicy. Coś jak dodanie klasy, która ma top:-2000px.

Użyłem JQuery, ponieważ też jestem leniwy, używam natywnego JS, ale nie jest to konieczne do tego, co zrobiłem.

Prawdopodobnie nie jest to najlepsze możliwe rozwiązanie, ponieważ górna zawartość po prostu przesuwa się w kierunku góry i nie można jej łatwo odzyskać, możesz zdecydowanie powinieneś użyć JQuery, jeśli naprawdę potrzebujesz animacji przewijania.

DEMO

 0
Author: Sir Celsius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-29 17:00:20

Oto czyste rozwiązanie css wykorzystujące jednostki viewport i zmienne, które automatycznie skalują się do urządzenia (i działają przy zmianie rozmiaru okna). Dodałem do rozwiązania Alexa:

        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)) );
 0
Author: user7915231,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-25 15:59:32

Zaimplementowałem odpowiedź zasugerowaną przez @user18490, ale napotkałem dwa problemy:

  • pierwsze odbijanie gdy użytkownik klika kilka kart/linków wielokrotnie w krótkim odstępie czasu
  • Po Drugie,undefined Błąd wymieniony przez @ krivar

Opracowałem następującą klasę, aby ominąć wspomniane problemy i działa dobrze: {]}

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

Jest problem z Firefoksem, jak wspomniano tutaj . Dlatego, aby działał na Firefoksie, zaimplementowałem następujący kod. Działa dobrze na przeglądarkach opartych na Chromium, a także Firefoksie.

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)
    }
}
 0
Author: user3405291,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-28 06:07:19