Anchor scrolling with pure js? - javascript

So all the solutions that I can find use jQuery. I understand it might be easier to use jQuery, but does anyone know of a pure Javascript method of anchor scrolling?
Codepen to get started: http://codepen.io/mildrenben/full/Kwwdzb/[1][1]
HTML:
<nav>
<ul>
<li>Section One</li>
<li>Section Two</li>
<li>Section Three</li>
<li>Section Four</li>
<li>Section Five</li>
</ul>
</nav>
<main>
<h1 id="section-one">SECTION ONE</h1>
<h1 id="section-two">SECTION TWO</h1>
<h1 id="section-three">SECTION THREE</h1>
<h1 id="section-four">SECTION FOUR</h1>
<h1 id="section-five">SECTION FIVE</h1>
</main>
CSS:
html, body {
width: 100%;
height: 100%;
}
* {
margin: 0;
font-family: sans-serif;
}
h1 {
margin-bottom: 300px;
}
nav {
width: calc(20% - 60px);
height: calc(100% - 60px);
background: aquamarine;
float: left;
padding: 30px;
overflow-y: scroll;
}
nav ul {
list-style: none;
}
nav li {
margin: 30px 0;
}
main {
width: calc(80% - 60px);
height: calc(100% - 60px);
background: darkseagreen;
float: left;
overflow-y: scroll;
padding: 30px;
}
main p {
width: 35%;
margin: 10px 0 70px;
}

Related

Transition menu closing with CSS or JS

I have a sidebar div and a content div that act as two CSS grid columns. The sidebar itself is composed of two more columns, but here's the gist of the setup:
<div class='site-wrap'>
<div class='sidebar'>
<div class='navbar'></div>
<div class='menu'>
<ul>
<li>menu item</li>
</ul>
</div>
</div>
<div class='content>
<h1>Hello world</h1></div>
</div>
</div>
Most of the CSS isn't important, but here's how the sidebar works:
.site-wrap {
display: grid;
grid-template-columns: 320px 1fr;
}
.sidebar {
display: grid;
grid-template-columns: 64px 1fr;
height: 100vh
}
Here's a JS Fiddle with a working implementation: https://jsfiddle.net/z4mLtwoy/
Currently, my solution to closing the menu is adding grid-template-columns: 72px 1fr to the site-wrap. This works, but I wish to add a transition. Since CSS grid doesn't have transitions yet, is there a CSS (maybe flexbox) or JS implementation that can offer a transition?
If you set a width or a max-width property to the menu element, it is possible to animate this property using CSS transitions. No need to use grids, you can use a flexbox layout to display them as columns.
body {
margin: 0;
padding: 0;
}
.site-wrap {
display: flex;
height: 100vh;
}
.sidebar {
display: flex;
}
.site-wrap .menu {
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
box-sizing: border-box;
height: 100vh;
margin: 0;
overflow: hidden;
padding: 0;
transition: max-width 0.5s ease;
max-width: 100px;
}
.site-wrap .navbar {
background: green;
height: 100vh;
width: 64px;
}
.menu li {
padding: 16px;
white-space: nowrap;
}
.content {
background: #EFEFEF;
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
flex-grow: 1;
padding: 16px;
}
.banner {
background: lightblue;
box-sizing: border-box;
padding: 16px;
height: 64px;
width: 100%;
}
#trigger {
display: none;
position: fixed;
}
.button {
background: blue;
color: white;
cursor: pointer;
margin: 8px;
padding: 8px 16px;
}
#trigger:checked ~ .site-wrap .menu {
max-width: 0px;
}
<input id='trigger' type='checkbox'>
<div class='banner'>
<label for='trigger' class='button'>Click me</label>
</div>
<div class='site-wrap'>
<div class='sidebar'>
<div class='navbar'></div>
<ul class='menu'>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
<div class='content'>
<h2>Hello world</h2>
</div>
</div>

Element width to match horizontal position of other element

Let's say we have a navigation div which contains elements. Below navigation div there is some bar that must expand to the width where it matches one of the navigation elements (3rd one in this case).
<div id="main_navigator">
<div id="main_navigator_upper">
<a id="main_navigator_logo" src="/"></a>
<ul id="main_navigator_r1">
<li>
<a class="main_nav_btn">BTN 1</a>
</li>
<li>
<a class="main_nav_btn">BTN 2</a>
</li>
<li>
<a class="main_nav_btn">BTN 3</a>
</li>
<li>
<a class="main_nav_btn">BTN 4</a>
</li>
<li id="main_navigator_l1">
<div id="main_navigator_s1"></div>
</li>
<li>
<ul id="main_navigator_regbox">
<li>
<p id="regbox_signin">sign in</p>
</li>
<li>
<div id="main_navigator_regbox_s1"></div>
</li>
<li>
<a id="regbox_signup" href="sign_up">sign up</a>
</li>
</ul>
</li>
</ul>
</div>
<div id="main_navigator_bottom">
<div id="main_navigator_progression"></div>
</div>
</div>
From this code, main_navigator_progression div must expand its width so it matches BTN 3.
You can see the concept here.
I've written a simple JS code, but it doesn't seem to be neat and doesn't always work:
function initializeProgressorPos() {
document.getElementById("main_navigator_progression").setAttribute("style", ("width: " + (document.getElementsByClassName("main_nav_btn")[2].getBoundingClientRect().x - document.getElementsByClassName("main_nav_btn")[2].getBoundingClientRect().width) + "px"))
}
initializeProgressorPos();
$(window).resize(function() {
initializeProgressorPos();
});
Is there any way to create such a function that works even when browser is scaled? What could be wrong with my code? Is there any chance that this can be done with pure css?
As you have floatted the element to the right, first you have to get the width of document, then exclude the width from left of document to the right of element from that amount:
function initializeProgressorPos() {
var elementRight=$(document).width()- $('.main_nav_btn:eq(2)').offset().left - $('.main_nav_btn:eq(2)').width();
$("#main_navigator_progression").css({"width": elementRight + "px"});
}
initializeProgressorPos();
$(window).resize(function() {
initializeProgressorPos();
});
body {
margin: 0;
overflow-y: scroll;
}
#main_navigator {
position: fixed;
background-color: black;
width: 100%;
}
#main_navigator_upper {
position: relative;
display: flex;
flex-direction: row;
}
#main_navigator_logo {
width: 416px;
height: 120px;
background-color: white;
}
#main_navigator_r1 {
display: flex;
flex-direction: row;
align-items: center;
flex-grow: 1;
flex-shrink: 1;
padding: 0;
padding-right: 5%;
text-align: center;
margin-top: 0px;
height: 98px;
list-style-type: none;
}
#main_navigator_r1 li {
flex-grow: 1;
flex-shrink: 1;
/* flex-basis: 0; */
flex-basis: auto; /* new */
}
#main_navigator_l1 {
flex-grow: 0.1 !important;
}
#main_navigator_r1 li .main_nav_btn {
color: white;
display: block;
height: 100%;
font-family: "nexa_bold";
font-size: 0.9em;
text-decoration: none;
}
#main_navigator_s1 {
display: inline-block;
width: 2px;
height: 35px;
background-color: #B28039;
}
#main_navigator_regbox {
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
list-style-type: none;
margin: 0px;
padding: 0px;
}
#main_navigator_regbox li {
display: inline-block;
flex-grow: 0.1;
flex-shrink: 0.1;
}
#regbox_signin {
display: block;
cursor: pointer;
white-space: nowrap;
text-decoration: none;
color: #B28039;
font-size: 0.9em;
font-family: "nexa_light";
}
#regbox_signup {
display: block;
white-space: nowrap;
text-decoration: none;
color: white;
font-size: 0.9em;
font-family: "nexa_light";
}
#main_navigator_regbox_s1 {
display: inline-block;
width: 1.4px;
height: 13.5px;
background-color: white;
}
#main_navigator_bottom {
background-color: black;
height: 24px;
}
#main_navigator_progression {
position: relative;
background-color: #B28039;
height: 100%;
width: 416px;
float: right;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<body>
<div id="main_navigator">
<div id="main_navigator_upper">
<a id="main_navigator_logo" src="/"></a>
<ul id="main_navigator_r1">
<li>
<a class="main_nav_btn">BTN 1</a>
</li>
<li>
<a class="main_nav_btn">BTN 2</a>
</li>
<li>
<a class="main_nav_btn">BTN 3</a>
</li>
<li>
<a class="main_nav_btn">BTN 4</a>
</li>
<li id="main_navigator_l1">
<div id="main_navigator_s1"></div>
</li>
<li>
<ul id="main_navigator_regbox">
<li>
<p id="regbox_signin">sign in</p>
</li>
<li>
<div id="main_navigator_regbox_s1"></div>
</li>
<li>
<a id="regbox_signup" href="sign_up">sign up</a>
</li>
</ul>
</li>
</ul>
</div>
<div id="main_navigator_bottom">
<div id="main_navigator_progression"></div>
</div>
</div>
</body>
</html>
This is a proof of concept.
You can use a combination of a custom HTML5 data-* attribute and an ::after pseudo-element on your navigation menu (and a dash of javascript) to indicate which menu item you have most recently selected.
Despite the dash of javascript, most of the work is done using CSS.
Working Example:
var menu = document.querySelector('nav ul');
var menuItems = [... menu.getElementsByTagName('li')];
function selectMenu() {
menu.dataset.selectedMenu = (menuItems.indexOf(this) + 1);
}
for (var i = 0; i < menuItems.length; i++) {
menuItems[i].addEventListener('click', selectMenu, false);
}
nav ul {
display: flex;
position: relative;
margin: 0;
padding: 0;
}
nav li {
flex: 0 0 60px;
padding: 12px 12px 24px;
color: rgb(255, 255, 255);
background-color: rgb(255, 0, 0);
list-style-type: none;
cursor: pointer;
}
nav ul::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 12px;
background-color: rgba(0, 0, 0, 0.5);
transition: width 0.6s linear;
}
nav ul[data-selected-menu="1"]::after {
width: 80px;
}
nav ul[data-selected-menu="2"]::after {
width: 160px;
}
nav ul[data-selected-menu="3"]::after {
width: 240px;
}
nav ul[data-selected-menu="4"]::after {
width: 320px;
}
nav ul[data-selected-menu="5"]::after {
width: 400px;
}
<nav>
<ul data-selected-menu="1">
<li class="active">Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
<li>Menu 5</li>
</ul>
</nav>

Tumblr: jquery doesn't work

I'm developing a Tumblr theme, but I have a problem with jquery.
When I use this bunch code outside of Tumbl it work like a charm, but when I use it on Tumblr nothing happen. How can I make it work on Tumblr too?
How you can see in the fiddle I want to add the class .smaller to the header when the article reach the top of the window.
thanks,
Filippo
// resize the header to small size
$(document).on("scroll", function(){
if
($(document).scrollTop() > $(window).height()){
$("header").addClass("smaller");
updateSliderMargin();
}
else
{
$("header").removeClass("smaller");
updateSliderMargin();
}
});
body {
text-align: center;
margin: 0;
padding: 0;
}
li {
display: inline;
}
header {
position: fixed;
top: 0;
width: 100%;
height: 150px;
background-color: red;
z-index: 99;
opacity: 0.8;
}
header.smaller {
height: 50px;
}
header.smaller ul {
display: none;
}
article {
position: relative;
top: 100vh;
background-color: green;
min-height: 1000px;
z-index: 1;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<body>
<header>
<h1>This is the Header</h1>
<ul>
<li>list 1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
</header>
<article>
<p>This is the Article</p>
</article>
</body>
Fiddle Demo
http://jsfiddle.net/z3cqkt9a/

Trouble Getting This Sliding Right

So here is my little HTML page with a playlist of videos:
http://jsfiddle.net/VvR4H/3/
As you can see, in the grey area I have an inline list of playlists, I have three now:
Kangaroo Fighting
Australian Sports
Real Football
Under each playlist are listed videos.
What I want to achieve is a nice horizontal scrolling between my playlists. Right now, when you click on the left or right corner of the grey playlist bar (where the text is half cut), it will slide to the other playlist.
However the sliding is not very nice. I want the Kangaroo Fighting to slide in the middle of the playlist bar when you click on the left corner, could you help me please?
Here is my HTML:
<div class="container">
<ul class="playlists">
<li class="playlist">
<div class="title"> <span class="move-left">Real Foorball</span>
<span>Kangaroo Fighting</span>
<span class="move-right">Australian Sports</span>
</div>
<ul class="videos">
<li class="video">Video 1 C</li>
<li class="video">Video 2 C</li>
<li class="video">Video 3 C</li>
</ul>
</li>
<li class="playlist">
<div class="title"> <span class="move-left">Kangaroo Fighting</span>
<span>Australian Sports</span>
<span class="move-right">Real Football</span>
</div>
<ul class="videos">
<li class="video">Video 1 A</li>
<li class="video">Video 2 A</li>
<li class="video">Video 3 A</li>
</ul>
</li>
<li class="playlist">
<div class="title"> <span class="move-left">Australian Sports</span>
<span>Real Football</span>
<span class="move-right">Kangaroo Fighting</span>
</div>
<ul class="videos">
<li class="video">Video 1 B</li>
<li class="video">Video 2 B</li>
<li class="video">Video 3 B</li>
</ul>
</li>
</ul>
</div>
My CSS:
ul li {
list-style: none;
}
.container {
position: relative;
background: #000;
width: 300px;
height: 500px;
overflow: hidden;
font-family: sans-serif;
}
ul.playlists {
width: 1200px;
padding-left: 0;
margin-top: 0;
position: absolute;
left: -300px;
}
ul.playlists li {
float: left;
width: 300px;
height: 50px;
}
ul.playlists li.playlist .title {
width: 100%;
background: grey;
color: white;
line-height: 50px;
text-align: center;
}
ul.playlists li.playlist .title .move-left, ul.playlists li.playlist .title .move-right {
width: 30px;
line-height: 50px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
}
ul.playlists li.playlist .title .move-left {
float: left;
direction: rtl;
}
ul.playlists li.playlist .title .move-right {
float: right;
}
ul.videos {
clear: both;
padding-left: 0;
}
ul.videos li {
float: left;
width: 250px;
height: 50px;
padding: 25px;
color: white;
background: blue;
border-top: 1px solid black;
}
And my JavaScript:
$(".move-left").click(function () {
$(this).parent().parent().parent().animate({
"left": "0"
}, 500, "linear", function () {
console.log("yay");
});
});
$(".move-right").click(function () {
$(this).parent().parent().parent().animate({
"left": "-600"
}, 500, "linear", function () {
console.log("yay");
});
});
It is not complete (I didnt do infinity loop), but I guess it has better animation as you requested.
I separated your html into 2 parts. First one is moving slower then second one. So you can se half text of next titles but you dont have to duplicate texts.
http://jsfiddle.net/VvR4H/10/
html
<div class="container">
<div class="title-wrapper">
<div class="title">
<span>Real Foorball</span>
<span>Kengoroo Fighting</span>
<span>Australian Sports</span>
</div>
</div>
<div class="playlist">
<ul class="videos">
<li class="video">Video 1 C</li>
<li class="video">Video 2 C</li>
<li class="video">Video 3 C</li>
</ul>
<ul class="videos">
<li class="video">Video 1 A</li>
<li class="video">Video 2 A</li>
<li class="video">Video 3 A</li>
</ul>
<ul class="videos">
<li class="video">Video 1 B</li>
<li class="video">Video 2 B</li>
<li class="video">Video 3 B</li>
</ul>
</div>
</div>
css
ul li {
list-style: none;
}
.container {
position: relative;
background: #000;
width: 300px;
height: 500px;
font-family: sans-serif;
overflow: hidden;
}
div.title-wrapper {
background: grey;
height: 50px;
}
div.title {
position: absolute;
overflow: hidden;
height: 50px;
left: 75px;
white-space: nowrap;
}
div.playlist {
position: absolute;
overflow: hidden;
top: 50px;
clear: both;
white-space: nowrap;
}
div.title span {
width: 300px;
background: grey;
color: white;
line-height: 50px;
text-align: left;
display: block;
float: left;
margin: 0;
padding: 0;
text-indent: 20px;
}
ul.videos {
float: left;
width: 300px;
margin: 0;
padding: 0;
}
ul.videos li {
display: block;
background: blue;
height: 50px;
padding: 10px 20px;
margin: 1px 0 0 0;
color: white;
}
javascript
$('.title span').css({
'text-indent' : '0',
'text-align' : 'center',
'width' : '150px'
});
var titles = [];
$('.title span').each( function () {
titles.push($(this));
});
var max = titles.length-1;
var left = max;
var right = 1;
$('.title span').click(function () {
console.log($(this).context.innerText + ' left: ' +titles[left].context.innerText + ' right: ' +titles[right].context.innerText)
if($(this).context==titles[left].context) {
left = (left==0) ? max : --left;
right = (right==0) ? max : --right;
$('.title').animate({
"left": "+=150px"
}, 500);
$('.playlist').animate({
"left": "+=300px"
}, 500);
}
if($(this).context==titles[right].context) {
left = (left==max) ? 0 : ++left;
right = (right==max) ? 0 : ++right;
$('.title').animate({
"left": "-=150px"
}, 500);
$('.playlist').animate({
"left": "-=300px"
}, 500);
}
});

jQuery - DIV to move with scrolling motion and stick position to top and bottom of window

There may be already a jQuery plugin which can achieve this, but I can't find one to do exactly what I'm after. If there is, just point me to the tutorial, thanks.
My problem I have is that I have very long page content, and my sidebar is not visible when you are scrolled near the bottom of the page.
So I would like to make my #sidebar div to stick to the top and bottom of my browser window as you scroll up and down the page.
My sidebar height is longer than your typical screen resolution, so I need the bottom of sidebar to sticky to the bottom of the browser window as well as the top of the browser.
So as you begin to scroll down, the side bar will scroll like normal, but when you reach the end the sidebar, it sticks and will not scroll, and as you begin to scroll up, the sidebar will follow until the top of sidebar reaches the browser, then it sticks. Vice Versa.
Is this possible?
I have created a jsfiddle of simple design layout which is central. I have added a dotted border to the sidebar so you now where the sidebar should stick.
http://jsfiddle.net/motocomdigital/7ey9g/5/
Any advice, or you know a online tutorial or demo, would most awesome!
UPDATE
Please see this attempt by #Darek Rossman
http://jsfiddle.net/dKDJz/4/
He's got the basic idea working. But the scrolling up, causes it to snap to the top. I need the sidebar to be fluid with the scrolling up/down motion. But sticking to the either the top or bottom of the window. It should also not be fixed positioned when the header/footer are in viewport, so it does not overlay.
Thanks
I have updated the jsfiddle with my solution.
var $sidebar = $("#sidebar"),
$window = $(window),
sidebartop = $("#sidebar").position().top;
$window.scroll(function() {
if ($window.height() > $sidebar.height()) {
$sidebar.removeClass('fixedBtm');
if($sidebar.offset().top <= $window.scrollTop() && sidebartop <= $window.scrollTop()) {
$sidebar.addClass('fixedTop');
} else {
$sidebar.removeClass('fixedTop');
}
} else {
$sidebar.removeClass('fixedTop');
if ($window.height() + $window.scrollTop() > $sidebar.offset().top + $sidebar.height()+20) {
$sidebar.addClass('fixedBtm');
}
if ($sidebar.offset().top < 0) {
$sidebar.removeClass('fixedBtm');
}
}
});
h1, h2 {
display: block;
font-weight: bold;
}
#horizon {
width: 100%;
height: 100%;
min-height: 100%;
background: #cccccc;
overflow: hidden;
}
#header, #footer {
width: 480px;
height: auto;
overflow: hidden;
background: teal;
padding: 10px;
color: #ffffff;
}
#wrapper {
width: 500px;
height: auto;
overflow: hidden;
background: #ffffff;
margin: 0 auto;
}
#content-wrapper {
width: 100%;
height: auto;
overflow: hidden:
}
#content {
width: 330px;
height: auto;
overflow: hidden;
background: #ffffff;
margin: 0 auto;
float: left;
padding: 10px;
}
#sidebar {
width: 130px;
height: auto;
overflow: hidden;
background: #ffffff;
margin: 0 auto;
float: left;
clear: right;
padding: 8px;
background: #e5e5e5;
border: 2px dashed red;
}
.fixedBtm {
margin-left: 350px !important;
position: fixed;
bottom: 0;
}
.fixedTop {
margin-left: 350px !important;
position: fixed;
top: 0;
}
.post {
margin: 5px;
width: 320px;
background: red;
float: none;
overflow: hidden;
min-height: 175px
}
.buttons li {
margin: 5px;
width: 120px;
background: blue;
float: none;
overflow: hidden;
min-height: 20px;
text-align: center;
color: #ffffff;
cursor: pointer;
}
.buttons li:hover {
background: lightblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="horizon">
<div id="wrapper">
<div id="header">header</div>
<div id="content-wrapper">
<div id="content">
<h1>Latest Posts</h1>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
<div class="post">This is a post</div>
</div>
<div id="sidebar">
<h2>Sidebar</h2>
<ul class="buttons">
<li>Button 1</li>
<li>Button 2</li>
<li>Button 3</li>
<li>Button 4</li>
<li>Button 5</li>
<li>Button 6</li>
<li>Button 7</li>
<li>Button 8</li>
<li>Button 9</li>
<li>Button 10</li>
<li>Button 11</li>
<li>Button 12</li>
<li>Button 13</li>
<li>Button 14</li>
<li>Button 15</li>
<li>Button 16</li>
<li>Button 17</li>
<li>Button 18</li>
</ul>
</div>
</div>
<div id="footer">footer</div>
</div>
</div>
The sidebar should remain in place at the top when the window is larger than the sidebar and fix to the bottom when the sidebar is larger.
You don't need any jQuery or javascript for this. All of this can be achieved in CSS with position: fixed.
Change your sidebar selector to the following
#sidebar {
width: 130px;
height: auto;
overflow: hidden;
background: #ffffff;
margin: 0 auto;
clear: right;
padding: 8px;
background: #e5e5e5;
border: 2px dashed red;
position: fixed;
right: 35px;
}

Categories