Menggulir dengan lancar saat mengklik tautan jangkar

487

Saya memiliki beberapa hyperlink di halaman saya. FAQ yang akan dibaca pengguna ketika mereka mengunjungi bagian bantuan saya.

Menggunakan tautan Jangkar, saya dapat membuat halaman menggulir ke arah jangkar dan memandu pengguna di sana.

Apakah ada cara untuk membuat pengguliran itu lancar?

Tetapi perhatikan bahwa dia menggunakan pustaka JavaScript khusus. Mungkin jQuery menawarkan sesuatu seperti ini?

Hanya orang Bolivia disini
sumber
Bisakah Anda tinjau jawaban terbaik? Solusi satu baris css murni sulit ditemukan di antara semua saran jquery besar: stackoverflow.com/a/51588820/1422553
Александр Киричек

Jawaban:

1160

Pembaruan April 2018: Sekarang ada cara asli untuk melakukan ini :

document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function (e) {
        e.preventDefault();

        document.querySelector(this.getAttribute('href')).scrollIntoView({
            behavior: 'smooth'
        });
    });
});

Saat ini hanya didukung di browser tepi paling berdarah.


Untuk dukungan browser yang lebih lama, Anda dapat menggunakan teknik jQuery ini:

$(document).on('click', 'a[href^="#"]', function (event) {
    event.preventDefault();

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top
    }, 500);
});

Dan ini biola: http://jsfiddle.net/9SDLw/


Jika elemen target Anda tidak memiliki ID, dan Anda menautkannya dengan ID name, gunakan ini:

$('a[href^="#"]').click(function () {
    $('html, body').animate({
        scrollTop: $('[name="' + $.attr(this, 'href').substr(1) + '"]').offset().top
    }, 500);

    return false;
});

Untuk peningkatan kinerja, Anda harus menyimpan cache $('html, body')pemilih itu, sehingga tidak berjalan setiap kali jangkar diklik:

var $root = $('html, body');

$('a[href^="#"]').click(function () {
    $root.animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top
    }, 500);

    return false;
});

Jika Anda ingin URL diperbarui, lakukan di dalam animatepanggilan balik:

var $root = $('html, body');

$('a[href^="#"]').click(function() {
    var href = $.attr(this, 'href');

    $root.animate({
        scrollTop: $(href).offset().top
    }, 500, function () {
        window.location.hash = href;
    });

    return false;
});
Joseph Silber
sumber
10
Ini tampaknya untuk menghapus ekstensi dari URL, melanggar fungsi kembali. Apakah ada jalan keluarnya?
Fletch
2
@JosephSilber harus tidak menjadi scrollTop: $(this.hash).offset().topbukan scrollTop: $(this.href).offset().top?
Gregory Pakosz
4
@CreateSean -scrollTop: $(href).offset().top - 72
Joseph Silber
5
Saya berpendapat bahwa cache html, bodyobjek di sini tidak perlu, menjalankan pemilih sekali per klik tidak terlalu banyak.
2
Solusi pertama adalah yang terbaik dan paling modern, Anda dapat menggunakan polyfill ini untuk mendukung perilaku ini di browser lama dengan polyfill
Efe
166

Sintaks yang benar adalah:

//Smooth scrolling with links
$('a[href*=\\#]').on('click', function(event){     
    event.preventDefault();
    $('html,body').animate({scrollTop:$(this.hash).offset().top}, 500);
});

// Smooth scrolling when the document is loaded and ready
$(document).ready(function(){
  $('html,body').animate({scrollTop:$(location.hash).offset().‌​top}, 500);
});

Menyederhanakan : KERING

function smoothScrollingTo(target){
  $('html,body').animate({scrollTop:$(target).offset().​top}, 500);
}
$('a[href*=\\#]').on('click', function(event){     
    event.preventDefault();
    smoothScrollingTo(this.hash);
});
$(document).ready(function(){
  smoothScrollingTo(location.hash);
});

Penjelasan tentang href*=\\#:

  • *berarti cocok dengan apa yang mengandung #char. Jadi hanya cocok dengan jangkar . Untuk lebih lanjut tentang arti ini, lihat di sini
  • \\karena itu #adalah char khusus di pemilih css, jadi kita harus menghindarinya.
Andres Separ
sumber
8
saya harus mengubah $('a')untuk $('a[href*=#]')hanya melayani jangkar url
okliv
2
@okliv Ini akan terlalu banyak ditayangkan, misalnya seperti tautan javascript <a href="javascript:$('#test').css('background-color', '#000')">Test</a>. Anda sebaiknya menggunakan $('a[href^=#]')untuk mencocokkan semua url yang dimulai dengan karakter hash.
Martin Braun
3
juga, '#' adalah karakter khusus dan perlu diloloskan seperti ini:a[href^=\\#]
QuinnFreedman
3
Ini menyebabkan tautan ke jangkar di halaman lain berhenti bekerja. Dipecahkan dengan menambahkan conditional if ($ ($ (this.hash) .selector) .length) {... smooth scroll. }
Liren
1
Bagaimana saya bisa menghidupkan ini ketika pertama kali bepergian ke halaman baru? Misalnya dengan mengklik: website.com/newpage/#section2. Saya ingin memuat halaman dan kemudian gulir ke bawah. Apakah itu mungkin?
Samyer
72

Panasnya baru di CSS3. Ini jauh lebih mudah daripada setiap metode yang tercantum pada halaman ini dan tidak memerlukan Javascript. Cukup masukkan kode di bawah ini ke Anda css dan semua tautan tiba-tiba menunjuk ke lokasi di dalam halaman Anda sendiri akan memiliki animasi bergulir mulus.

html{scroll-behavior:smooth}

Setelah itu, semua tautan yang mengarah ke div akan meluncur dengan lancar ke bagian-bagian tersebut.

<a href="#section">Section1</a>

Sunting: Bagi yang bingung dengan tag di atas. Pada dasarnya ini adalah tautan yang dapat diklik. Anda kemudian dapat memiliki tag div lain di suatu tempat di halaman web Anda suka

<div classname="section">content</div>

Dalam hal ini tautan akan dapat diklik dan akan menuju ke bagian apa pun, dalam hal ini adalah bagian kami yang kami sebut bagian.

BTW, saya menghabiskan berjam-jam mencoba untuk mendapatkan ini berfungsi. Menemukan solusinya di bagian komentar yang tidak jelas. Itu buggy dan tidak akan bekerja di beberapa tag. Tidak bekerja di dalam tubuh. Akhirnya berhasil ketika saya memasukkannya ke dalam html {} dalam file CSS.

Cristian Reyes
sumber
4
Saya bisa sangat berguna tetapi mereka kekurangannya
Buzut
3
bagus, tapi hati-hati karena saat ini tidak didukung oleh Safari dan jelas oleh Explorer (03/2019)
Marco Romano
2
solusi yang bagus, hanya cakupannya dengan 74,8% terbatas. mungkin di masa depan
iepur1lla
1
Itu luar biasa. Terima kasih banyak.
Mikkel Fennefoss
1
Ini akan menjadi jawaban yang paling relevan di tahun-tahun mendatang.
Nurul Huda
22
$('a[href*=#]').click(function(event){
    $('html, body').animate({
        scrollTop: $( $.attr(this, 'href') ).offset().top
    }, 500);
    event.preventDefault();
});

ini bekerja sempurna untuk saya

Philipp Sander
sumber
1
"event.preventDefault ();" dapat menggantikan "return false;"
Andres Separated
Maaf untuk mengatakan, tetapi tidak bekerja dan tampil di halaman bernama jangkar dengan cepat tanpa kelancaran.
Kamlesh
18

Saya terkejut tidak ada yang memposting solusi asli yang juga menangani pembaruan hash lokasi browser agar sesuai. Ini dia:

let anchorlinks = document.querySelectorAll('a[href^="#"]')
 
for (let item of anchorlinks) { // relitere 
    item.addEventListener('click', (e)=> {
        let hashval = item.getAttribute('href')
        let target = document.querySelector(hashval)
        target.scrollIntoView({
            behavior: 'smooth',
            block: 'start'
        })
        history.pushState(null, null, hashval)
        e.preventDefault()
    })
}

Lihat tutorial: http://www.javascriptkit.com/javatutors/scrolling-html-bookmark-javascript.shtml

Untuk situs dengan header lengket, scroll-padding-topCSS dapat digunakan untuk memberikan offset.

kepulan coco
sumber
1
Saya paling suka jawaban ini. Namun afais tidak ada cara untuk memberikan offset. Seperti yang akan diperlukan dalam kasus header tetap.
bskool
Sayangnya, dukungan buruk yang sama seperti untuk properti perilaku scroll CSS: developer.mozilla.org/en-US/docs/Web/CSS/…
Dmitry Nevzorov
15

Hanya CSS

html {
    scroll-behavior: smooth !important;
}

Yang perlu Anda tambahkan hanya ini. Sekarang perilaku pengguliran tautan internal Anda akan menjadi lancar seperti aliran-arus.

Catatan : Semua browser terbaru ( Opera, Chrome, Firefoxdll) mendukung fitur ini.

untuk pemahaman detail, baca artikel ini

WasiF
sumber
1
bagus! Mengapa ini bukan jawaban yang diterima? kita tidak perlu semua javascript itu!
Trevor de Koekkoek
1
Ini bekerja dengan baik, ini harus menjadi jawaban yang diterima.
makam
Periksa dukungan browser di sini
Ryan Zhou
1
ini bekerja seperti pesona. tidak perlu untuk js
Navbro
Ini adalah solusi terbaik untuk pengguliran yang mulus yang pernah ada! Terima kasih!
yehanny
10

Saya sarankan Anda membuat kode umum ini:

$('a[href^="#"]').click(function(){

var the_id = $(this).attr("href");

    $('html, body').animate({
        scrollTop:$(the_id).offset().top
    }, 'slow');

return false;});

Anda dapat melihat artikel yang sangat bagus di sini: jquery-effet-smooth-scroll-defilement-fluide

sarah bouyer
sumber
9
Ini bukan generik, ini jQuery.
AnrDaemon
6
$(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top
        }, 1000);
        return false;
      }
    }
  });
});

Resmi: http://css-tricks.com/snippets/jquery/smooth-scrolling/

KingRider
sumber
1
ini sepertinya hanya berfungsi untuk tautan anchor halaman dalam, tetapi tautan anchor dari halaman lain tidak berfungsi, misalnya situs
web.com/about-us/#who-we-are
5

Sudah ada banyak jawaban bagus di sini - namun semuanya kehilangan fakta bahwa jangkar kosong harus dikecualikan . Kalau tidak, skrip-skrip tersebut menghasilkan kesalahan JavaScript segera setelah jangkar kosong diklik.

Menurut pendapat saya, jawaban yang benar adalah seperti ini:

$('a[href*=\\#]:not([href$=\\#])').click(function() {
    event.preventDefault();

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top
    }, 500);
});
Blackbam
sumber
4

Menggunakan JQuery:

$('a[href*=#]').click(function(){
  $('html, body').animate({
    scrollTop: $( $.attr(this, 'href') ).offset().top
  }, 500);
  return false;
});
brequinn
sumber
3

Jawaban yang diberikan berfungsi tetapi menonaktifkan tautan keluar. Di bawah versi dengan bonus tambahan memudahkan keluar (ayunan) dan menghormati tautan keluar.

$(document).ready(function () {
    $('a[href^="#"]').on('click', function (e) {
        e.preventDefault();

        var target = this.hash;
        var $target = $(target);

        $('html, body').stop().animate({
            'scrollTop': $target.offset().top
        }, 900, 'swing', function () {
            window.location.hash = target;
        });
    });
});
Rick
sumber
+1 untuk stop()remah url tidak berfungsi seperti yang diharapkan: tombol Kembali tidak membawa kembali, ini karena ketika remah diatur dalam url setelah animasi selesai. Lebih baik tanpa remah-remah di url, misalnya begitulah cara airbnb.
Eric
3

HTML

<a href="#target" class="smooth-scroll">
    Link
</a>
<div id="target"></div>

atau Dengan URL Lengkap absolut

<a href="https://somewebsite.com/#target" class="smooth-scroll">
    Link
</a>
<div id="target"></div>

jQuery

$j(function() {
    $j('a.smooth-scroll').click(function() {
        if (
                window.location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '')
            &&  window.location.hostname == this.hostname
        ) {
            var target = $j(this.hash);
            target = target.length ? target : $j('[name=' + this.hash.slice(1) + ']');
            if (target.length) {
                $j('html,body').animate({
                    scrollTop: target.offset().top - 70
                }, 1000);
                return false;
            }
        }
    });
});
Jasmeet Singh
sumber
3

Browser modern sedikit lebih cepat akhir-akhir ini. SetInterval mungkin berfungsi. Fungsi ini bekerja dengan baik di Chrome dan Firefox hari ini. (Agak lambat dalam safari, tidak repot dengan IE)

function smoothScroll(event) {
    if (event.target.hash !== '') { //Check if tag is an anchor
        event.preventDefault()
        const hash = event.target.hash.replace("#", "")
        const link = document.getElementsByName(hash) 
        //Find the where you want to scroll
        const position = link[0].getBoundingClientRect().y 
        let top = 0

        let smooth = setInterval(() => {
            let leftover = position - top
            if (top === position) {
                clearInterval(smooth)
            }

            else if(position > top && leftover < 10) {
                top += leftover
                window.scrollTo(0, top)
            }

            else if(position > (top - 10)) {
                top += 10
                window.scrollTo(0, top)
            }

        }, 6)//6 milliseconds is the faster chrome runs setInterval
    }
}
littleboots
sumber
3

Ada cara css untuk melakukan ini menggunakan perilaku scroll. Tambahkan properti berikut.

    scroll-behavior: smooth;

Dan itu dia. Tidak diperlukan JS.

a {
  display: inline-block;
  width: 50px;
  text-decoration: none;
}
nav, scroll-container {
  display: block;
  margin: 0 auto;
  text-align: center;
}
nav {
  width: 339px;
  padding: 5px;
  border: 1px solid black;
}
scroll-container {
  display: block;
  width: 350px;
  height: 200px;
  overflow-y: scroll;
  scroll-behavior: smooth;
}
scroll-page {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-size: 5em;
}
<nav>
  <a href="#page-1">1</a>
  <a href="#page-2">2</a>
  <a href="#page-3">3</a>
</nav>
<scroll-container>
  <scroll-page id="page-1">1</scroll-page>
  <scroll-page id="page-2">2</scroll-page>
  <scroll-page id="page-3">3</scroll-page>
</scroll-container>

PS: silakan periksa kompatibilitas browser.

Santosh
sumber
ke wadah mana saya harus menggunakan scroll-behaviour: smooth;
CraZyDroiD
Jika ragu, tambahkan ke tag tubuh @CraZyDroiD
Santosh
2

Menambahkan ini:

function () {
    window.location.hash = href;
}

entah bagaimana membatalkan offset vertikal

top - 72

di Firefox dan IE, ut bukan di Chrome. Pada dasarnya, halaman bergulir dengan lancar ke titik di mana ia harus berhenti berdasarkan offset, tetapi kemudian melompat ke bawah ke mana halaman akan pergi tanpa offset.

Itu menambahkan hash ke akhir url, tetapi menekan kembali tidak membawa Anda kembali ke atas, itu hanya menghilangkan hash dari url dan meninggalkan jendela penglihatan di mana ia duduk.

Inilah js lengkap yang saya gunakan:

var $root = $('html, body');
$('a').click(function() {
    var href = $.attr(this, 'href');
    $root.animate({
        scrollTop: $(href).offset().top - 120
    }, 500, function () {
        window.location.hash = href;
    });
    return false;
});
Reid
sumber
2

Solusi ini juga akan berfungsi untuk URL berikut, tanpa memutus tautan anchor ke halaman yang berbeda.

http://www.example.com/dir/index.html
http://www.example.com/dir/index.html#anchor

./index.html
./index.html#anchor

dll.

var $root = $('html, body');
$('a').on('click', function(event){
    var hash = this.hash;
    // Is the anchor on the same page?
    if (hash && this.href.slice(0, -hash.length-1) == location.href.slice(0, -location.hash.length-1)) {
        $root.animate({
            scrollTop: $(hash).offset().top
        }, 'normal', function() {
            location.hash = hash;
        });
        return false;
    }
});

Saya belum menguji ini di semua browser.

Midas
sumber
2

Ini akan membuatnya mudah untuk mengizinkan jQuery untuk melihat hash target Anda dan tahu kapan dan di mana harus berhenti.

$('a[href*="#"]').click(function(e) {
    e.preventDefault();
    var target = this.hash;
    $target = $(target);

    $('html, body').stop().animate({
        'scrollTop': $target.offset().top
    }, 900, 'swing', function () {
        window.location.hash = target;
    });
});
PanicBus
sumber
2
$("a").on("click", function(event){
    //check the value of this.hash
    if(this.hash !== ""){
        event.preventDefault();

        $("html, body").animate({scrollTop:$(this.hash).offset().top}, 500);

        //add hash to the current scroll position
        window.location.hash = this.hash;

    }



});
Abk
sumber
2

Kode yang Diuji dan Diverifikasi

<script>
jQuery(document).ready(function(){
// Add smooth scrolling to all links
jQuery("a").on('click', function(event) {

// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
  // Prevent default anchor click behavior
  event.preventDefault();

  // Store hash
  var hash = this.hash;

  // Using jQuery's animate() method to add smooth page scroll
  // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
  jQuery('html, body').animate({
    scrollTop: jQuery(hash).offset().top
  }, 800, function(){

    // Add hash (#) to URL when done scrolling (default click behavior)
    window.location.hash = hash;
  });
} // End if
});
});
</script>
Atif Tariq
sumber
1

Saya melakukan ini untuk jangkar href "/ xxxxx # asdf" dan "#asdf"

$("a[href*=#]").on('click', function(event){
    var href = $(this).attr("href");
    if ( /(#.*)/.test(href) ){
      var hash = href.match(/(#.*)/)[0];
      var path = href.match(/([^#]*)/)[0];

      if (window.location.pathname == path || path.length == 0){
        event.preventDefault();
        $('html,body').animate({scrollTop:$(this.hash).offset().top}, 1000);
        window.location.hash = hash;
      }
    }
});
AndreDurao
sumber
1

Inilah solusi yang saya terapkan untuk banyak tautan dan jangkar, untuk gulir yang lancar:

http://www.adriantomic.se/development/jquery-localscroll-tutorial/ jika Anda mengatur tautan navigasi di div navigasi dan menyatakan dengan struktur ini:

<a href = "#destinationA">

dan tujuan tag anchor yang sesuai adalah:

<a id = "destinationA">

Kemudian muat saja ini ke kepala dokumen:

    <!-- Load jQuery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>

<!-- Load ScrollTo -->
<script src="http://flesler-plugins.googlecode.com/files/jquery.scrollTo-1.4.2-min.js"></script>

<!-- Load LocalScroll -->
<script src="http://flesler-plugins.googlecode.com/files/jquery.localscroll-1.2.7-min.js"></script>

<script type = "text/javascript">
 $(document).ready(function()
    {
        // Scroll the whole document
        $('#menuBox').localScroll({
           target:'#content'
        });
    });
</script>

Terima kasih kepada @Adriantomic

collyg
sumber
1

Jika Anda memiliki tombol sederhana di halaman untuk menggulir ke bawah ke div dan ingin tombol kembali berfungsi dengan melompat ke atas, tambahkan saja kode ini:

$(window).on('hashchange', function(event) {
    if (event.target.location.hash=="") {
        window.scrollTo(0,0);
    }
});

Ini dapat diperluas untuk melompat ke div yang berbeda juga, dengan membaca nilai hash, dan menggulir seperti Joseph Silbers menjawab.

Niclas
sumber
1

Jangan pernah lupa bahwa fungsi offset () memberi posisi elemen Anda pada dokumen. Jadi ketika Anda perlu menggulir elemen Anda relatif terhadap induknya, Anda harus menggunakan ini;

    $('.a-parent-div').find('a').click(function(event){
        event.preventDefault();
        $('.scroll-div').animate({
     scrollTop: $( $.attr(this, 'href') ).position().top + $('.scroll-div').scrollTop()
     }, 500);       
  });

Titik kuncinya adalah mendapatkan scrollTop dari scroll-div dan menambahkannya ke scrollTop. Jika Anda tidak akan melakukan fungsi posisi itu () selalu memberi Anda nilai posisi yang berbeda.

rotring05
sumber
1

Anda dapat menggunakan window.scroll()dengan behavior: smoothdan topmengatur ke atas offset jangkar yang memastikan bahwa tag jangkar akan berada di bagian atas viewport.

document.querySelectorAll('a[href^="#"]').forEach(a => {
    a.addEventListener('click', function (e) {
        e.preventDefault();
        var href = this.getAttribute("href");
        var elem = document.querySelector(href)||document.querySelector("a[name="+href.substring(1, href.length)+"]");
        //gets Element with an id of the link's href 
        //or an anchor tag with a name attribute of the href of the link without the #
        window.scroll({
            top: elem.offsetTop, 
            left: 0, 
            behavior: 'smooth' 
        });
        //if you want to add the hash to window.location.hash
        //you will need to use setTimeout to prevent losing the smooth scrolling behavior
       //the following code will work for that purpose
       /*setTimeout(function(){
            window.location.hash = this.hash;
        }, 2000); */
    });
});

Demo:

Anda bisa mengatur properti CSS scroll-behaviorke smooth(yang didukung sebagian besar browser modern) yang menyingkirkan kebutuhan untuk Javascript.

hev1
sumber
0

terima kasih sudah berbagi, Joseph Silber. Di sini solusi 2018 Anda sebagai ES6 dengan sedikit perubahan untuk menjaga perilaku standar (gulir ke atas):

document.querySelectorAll("a[href^=\"#\"]").forEach((anchor) => {
  anchor.addEventListener("click", function (ev) {
    ev.preventDefault();

    const targetElement = document.querySelector(this.getAttribute("href"));
    targetElement.scrollIntoView({
      block: "start",
      alignToTop: true,
      behavior: "smooth"
    });
  });
});
Motine
sumber
0

Memerlukan jquery dan animasi untuk melabuhkan tag dengan nama yang ditentukan alih-alih id, sambil menambahkan hash ke url browser. Juga memperbaiki kesalahan dalam sebagian besar jawaban dengan jquery di mana tanda # tidak diawali dengan backslash yang lolos. Tombol kembali, sayangnya, tidak menavigasi kembali dengan benar ke tautan hash sebelumnya ...

$('a[href*=\\#]').click(function (event)
{
    let hashValue = $(this).attr('href');
    let name = hashValue.substring(1);
    let target = $('[name="' + name + '"]');
    $('html, body').animate({ scrollTop: target.offset().top }, 500);
    event.preventDefault();
    history.pushState(null, null, hashValue);
});
jjxtra
sumber