Scrolling to an Anchor using Transition/CSS3

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

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

I am using the following 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.

Any help/ideas would be greatly appreciated.


You can use the scroll-behavior CSS property (which is supported in all browsers except Internet Explorer and Safari):

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>

You can find the answer to your question on the following page:

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

Here is the JSFiddle that was given:

http://jsfiddle.net/YYPKM/3/

Note the scrolling section at the end of the CSS, specifically:

/*
 *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>

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.

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:

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 code:

<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.

Thanks everyone for your help.

Knowing a bit of coding can help you avoiding (sometimes heavy) libraries, and giving you (the programmer) more control.