Currently I have a header element with the following code
<header>
<div class="container">
<div class="row" style="display: flex; justify-content: center">
<div class="col-xs-12 text-center" style="align-self: center">
<h1>My header</h1>
<span id="slogan">my slogan</span>
</div>
</div>
</div>
</header>
The header element starts at the beginning of body and ends 75 px short of the window bottom.
header {
height: calc(100vh - 75px);
}
When I start scrolling downwards, the header element starts moving up with the header and the slogan span. However, I want to keep the h1 and span elements vertically centered to the visible part of the header element, somewhat like on the iStockPhoto website. Notice how you scroll down the search form stays vertically centered to the background image container.
How do I implement something similar?
After a little bit of trial and error I created the effect with the following code.
<header>
<div class="container">
<div class="row" style="display: flex; justify-content: center">
<div class="col-xs-12 text-center" style="align-self: center">
<h1>Header</h1>
<span id="slogan">my slogan</span>
</div>
</div>
</div>
</header>
<section style="height: 1000px">
<div class="container">
<div class="row">
<div class="col-xs-12">
<p>Lorem ipsum dolor sit amet...</p>
</div>
</div>
</div>
</section>
$(function() {
var initialTitleHeight = $("header h1").position().top,
initialSloganBottom = $("header span").position().top + $("header span").height(),
headerHeight = $("header").height(),
headerMaxMargin = headerHeight - (initialSloganBottom - initialTitleHeight + 50);
$(window).scroll(function(event) {
var scroll = $(window).scrollTop(),
marginTop = (initialTitleHeight + scroll < headerMaxMargin) ? initialTitleHeight + scroll : headerMaxMargin;
$("header h1").css({
marginTop: marginTop + "px"
});
});
})
header {
height: calc(100vh - 75px);
background-color: #F90;
.container, .row {
height: 100%;
}
}
You can try it here.
Related
I have this script that changes the image(s) when the text reaches the top of the screen. I want it in reverse. I would like to have the image(s) change when the text becomes visible from a certain height (say 50px) from bottom. How do I go about this?
JS Fiddle: https://jsfiddle.net/ramo427e/
HTML:
<div class="main">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>This is sparta and what comes whatever after. This is sparta and what comes whatever after. This is sparta and what comes whatever after. </h1><h1>This is sparta and what comes whatever after. This is sparta and what comes whatever after. This is sparta and what comes whatever after. </h1>
</div>
<div class="col-md-6">
<section id="one">
<div class="content">
<h1>first heading</h1>
<p>description</p>
</div>
</section>
<section id="two">
<div class="content">
<h1>second heading</h1>
<p>description</p>
</div>
</section>
<section id="three">
<div class="content">
<h1>third heading</h1>
<p>description</p>
</div>
</section>
<section id="four">
<div class="content">
<h1>fourth heading</h1>
<p>description</p>
</div>
</section>
</div>
<div class="col-md-6">
<div class="image"></div>
</div>
</div>
<div class="row">
<div class="col-12">
<h1>This is sparta and what comes whatever after. This is sparta and what comes whatever after. This is sparta and what comes whatever after. </h1>
</div>
</div>
</div>
</div>
CSS:
*{
margin:0;
padding:0;
}
h1{
font-size: 18px;
font-weight: strong;
}
p{
font-size: 12px;
}
.main{
width:100%;
height:auto;
position: relative;
}
.image {
background-image:url('https://i.postimg.cc/FRxNp6yG/hr-ax.png');
background-size:100% 100%;
background-attachment:fixed;
transition: 1000ms;
width: 200px;
height: 200px;
position: fixed;
}
#one, #two, #three, #four {
min-height: 150px;
}
JS:
$(window).on("scroll touchmove", function() {
if ($(document).scrollTop() >= $("#one").position().top && $(document).scrollTop() < $("#two").position().top) {
$('.image').css('background-image', 'url(https://i.postimg.cc/FRxNp6yG/hr-ax.png)')
};
if ($(document).scrollTop() >= $("#two").position().top && $(document).scrollTop() < $("#three").position().top) {
$('.image').css('background-image', 'url(https://i.postimg.cc/wvz9hzm7/hr-bx.png)')
};
if ($(document).scrollTop() >= $("#three").position().top && $(document).scrollTop() < $("#four").position().top) {
$('.image').css('background-image', 'url(https://i.postimg.cc/FRxNp6yG/hr-ax.png)')
};
if ($(document).scrollTop() >= $("#four").position().top) {
$('.image').css('background-image', 'url(https://i.postimg.cc/wvz9hzm7/hr-bx.png)')
};
});
on the scroll, you can get the position of the all element. And calculate whether it is visible or not. Based on the switch case you can change image.
Sample:
window.addEventListener('scroll', function() {
var element = document.querySelector('#main-container');
var position = element.getBoundingClientRect();
// checking whether fully visible
if(position.top >= 0 && position.bottom <= window.innerHeight) {
console.log('Element is fully visible in screen');
}
// checking for partial visibility
if(position.top < window.innerHeight && position.bottom >= 0) {
console.log('Element is partially visible in screen');
}
});
More:
https://usefulangle.com/post/113/javascript-detecting-element-visible-during-scroll
Select the text with jQuery and correct the height relative to that and use that to trigger the event for Example:
if($(document).scrollTop() >= $("#one .content h1").position().top - 50){
$('.image').css('background-image', 'url(https://i.postimg.cc/FRxNp6yG/hr-ax.png)')
}
Is there any way to modify DOM based on amount div after specific class?
For example, if I have a div with a class called row and after that I have 4 div elements. Is there a way to change these 4 div element class depending on how many div elements there are?
Code:
<div class="row">
<div class="col-1-of-4">
some content
</div>
<div class="col-1-of-4">
some content
</div>
<div class="col-1-of-4">
some content
</div>
<div class="col-1-of-4">
some content
</div>
</div>
Another example I have a div class row again, but this time I want 3 div elements after that, then I would want these div elements to have a class called col-1-of-3, not col-1-of-4. If I would have just 2 div elements after that then class col-1-of-2 and if just one div element then no class at all.:
Code:
<div class="row">
<div class="col-1-of-3">
some content
</div>
<div class="col-1-of-3">
some content
</div>
<div class="col-1-of-3">
some content
</div>
</div>
Also these div elements with classes called col-1-of-4, col-1-of-3 and col-1-of-2 have their own div elements inside them, but they should stay like they were.
Is it possible to achieve with JavaScript or PHP?
You would need to write conditional blocks to handle this if I'm understanding you correctly (wanting a JS or PHP solution).
Note: It goes without saying that a similar solution can be completed with a CSS-only approach, as outlined here: Can CSS detect the number of children an element has?
Here's an example (using jQuery) with 3 sets of row's, with varying children (2, 3, 4):
$(function() {
var $rows = $(".row");
$rows.each(function() {
$row = $(this);
var $children = $(">div", $row),
total = $children.size();
$children.addClass("col-1-of-" + total);
});
});
.row {
border: 1px solid #000;
margin: 10px;
}
.row > div {
margin: 10px;
}
.row .col-1-of-2 {
border: 1px solid #f00;
}
.row .col-1-of-3 {
border: 1px solid #0f0;
}
.row .col-1-of-4 {
border: 1px solid #00f;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div>
some content
</div>
<div>
some content
</div>
</div>
<div class="row">
<div>
some content
</div>
<div>
some content
</div>
<div>
some content
</div>
</div>
<div class="row">
<div>
some content
</div>
<div>
some content
</div>
<div>
some content
</div>
<div>
some content
</div>
</div>
When you run the snippet, you must inspect the elements. I've added borders so you can see the difference.
Theres a number of ways to achieve this. I'd maybe add another class name so you can easily identify groups of divs, and differentiate between parent and child divs. Does this help you get where you're going? Basically find the number of children in a row and then concatenate that number into the class name.
var x = document.getElementsByClassName('row')[0].childElementCount
var element = document.getElementsByClassName('row')[0];
element.classList.add(`col-1-of-${x}`);
.row {
width: 100%;
display:flex;
flex-grow: 1;
margin-bottom: 2px;
}
.col {
float:left;
background: rgba(255,0,0,.2);
text-align: center;
margin-right: 2px;
}
.col:first-child:nth-last-child(1),
.col:first-child:nth-last-child(1) ~ .col{
width: calc(100% / 1);
}
.col:first-child:nth-last-child(2),
.col:first-child:nth-last-child(2) ~ .col{
width: calc(100% / 2);
}
.col:first-child:nth-last-child(3),
.col:first-child:nth-last-child(3) ~ .col{
width: calc(100% / 3);
}
.col:first-child:nth-last-child(4),
.col:first-child:nth-last-child(4) ~ .col{
width: calc(100% / 4);
}
.col:first-child:nth-last-child(5),
.col:first-child:nth-last-child(5) ~ .col{
width: calc(100% / 5);
}
<div class="row">
<div class="col">1</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
</div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>
so this is with float, can be used in a sass/scss mixin to create code automagically. there should be also a flex solution but i dont have it at hand at the moment
I am trying to implement a simple button that on click will scroll the page either up or down 100vh between my sections. I can see plenty of examples doing this with jQuery but I'm looking for a pure javascript solution. I'm not to sure how to achieve it.
Appreciate any advice.
HTML
<section class="section section-1">
<div class="btn"></div>
</section>
<section class="section section-2">
<div class="btn"></div>
</section>
<section class="section section-3">
<div class="btn"></div>
</section>
CSS
.section {
width: 100%;
height: 100vh:
}
This is what I have come up with so far
for (var s = 0; s < btn.length; s++) {
btn[s].addEventListener('click', function(){
window.scrollBy(0,1000);
});
}
There are a few ways to get viewport size in JavaScript. Using one of these ways, you should be able to scroll as you are with the viewport size in place of your 1000.
For instance, if I wanted to scroll exactly the height of one viewport with window.innerHeight:
let pageHeight = window.innerHeight;
window.scrollBy(0, pageHeight);
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', function() {
let scrollDistance = document.documentElement.clientHeight;
if (btn.className.split(' ').includes('scroll-up')) {
scrollDistance *= -1;
}
window.scrollBy(0, scrollDistance);
});
});
body {
margin: 0;
}
.section {
width: 100%;
height: 100vh;
}
.section-1 {
background-color: blue;
}
.section-2 {
background-color: red;
}
.section-3 {
background-color: green;
}
<section class="section section-1">
<div class="btn scroll-down">V</div>
<div class="btn scroll-up">^</div>
</section>
<section class="section section-2">
<div class="btn scroll-down">V</div>
<div class="btn scroll-up">^</div>
</section>
<section class="section section-3">
<div class="btn scroll-down">V</div>
<div class="btn scroll-up">^</div>
</section>
I have a code similar to:
<div id='right-column'>
<div id='results'>
<div id='result1>
<div class='main'></div>
<div class='details'></div>
</div>
<!-- ... -->
<div id='result50>
<div class='main'></div>
<div class='details'></div>
</div>
</div>
</div>
the total number of results depends of the ajax query, I insert all the results dynamically in one go.
div.main is always visible (fixed height) and div.details "unfolds/folds" below div.main when the user clicks on a result div.
the details div height can vary.
If #results scrollHeight is bigger than #right-column height, I would like to create a continuous scroll loop.
In this case, scrolling past #result50 would show #result1, scrolling before #result1 would show #result50.
I can't .append() the first child to the bottom as in some cases a portion of a result can be seen on top and at the bottom of the column.
I can't duplicate a result unless I detect if .details is unfolded/folded.
The fact that the height of a result can change when a user unfolds the .details div, makes it even more complicated...
Here is an example of continuous scroll loop (2 columns):
$(document).ready(function() {
var num_children = $('#up-left').children().length;
var child_height = $('#up-left').height() / num_children;
var half_way = num_children * child_height / 2;
$(window).scrollTop(half_way);
function crisscross() {
$('#up-left').css('bottom', '-' + window.scrollY + 'px');
$('#down-right').css('bottom', '-' + window.scrollY + 'px');
var firstLeft = $('#up-left').children().first();
var lastLeft = $('#up-left').children().last();
var lastRight = $('#down-right').children().last();
var firstRight = $('#down-right').children().first();
if (window.scrollY > half_way ) {
$(window).scrollTop(half_way - child_height);
lastRight.appendTo('#up-left');
firstLeft.prependTo('#down-right');
} else if (window.scrollY < half_way - child_height) {
$(window).scrollTop(half_way);
lastLeft.appendTo('#down-right');
firstRight.prependTo('#up-left');
}
}
$(window).scroll(crisscross);
});
div#content {
width: 100%;
height: 100%;
position: absolute;
top:0;
right:0;
bottom:0;
left:0;
}
#box {
position: relative;
vertical-align:top;
width: 100%;
height: 200px;
margin: 0;
padding: 0;
}
#up-left {
position:absolute;
z-index:4px;
left: 0;
top: 0px;
width: 50%;
margin: 0;
padding: 0;
}
#down-right {
position:fixed;
bottom: 0px;
z-index: 5px;
left: 50%;
width: 50%;
margin: 0;
padding: 0;
}
h1 {margin: 0;padding: 0;color:#fff}
.black {background: black;}
.white {background: grey;}
.green {background: green;}
.brown {background: brown;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div id="content">
<div id="up-left">
<div id="box" class="brown">
<h1>ONE</h1>
</div>
<div id="box" class="black">
<h1>TWO</h1>
</div>
<div id="box" class="white">
<h1>THREE</h1>
</div>
<div id="box" class="black">
<h1>FOUR</h1>
</div>
<div id="box" class="white">
<h1>FIVE</h1>
</div>
<div id="box" class="black">
<h1>SIX</h1>
</div>
</div><!-- #up-left -->
<div id="down-right">
<div id="box" class="white">
<h1>SIX</h1>
</div>
<div id="box" class="black">
<h1>FIVE</h1>
</div>
<div id="box" class="white">
<h1>FOUR</h1>
</div>
<div id="box" class="black">
<h1>THREE</h1>
</div>
<div id="box" class="white">
<h1>TWO</h1>
</div>
<div id="box" class="green">
<h1>ONE</h1>
</div>
</div><!-- #down-right -->
</div><!-- .content -->
(fiddle: http://jsfiddle.net/franckl/wszg1d6c/)
Any hint/ideas on how I could do it ?
Move items to top or bottom based on scroll direction
You can use jQuery's .append() and .prepend() to move items without cloning them.
You'll use similar techniques to infinite scrolling with lazy loading (AJAX), but in this scenario you want to handle scrolling up as well as down, and instead of loading new content from the server, you're just recycling existing DOM elements in the list.
Below I demonstrate one technique. I store the scroll position in the element's .data cache for easy retrieval when detecting scrolling direction. I chose to detect scrolling direction to avoid making unnecessary variable assignments upfront to improve performance. Otherwise, you'd be getting elements and doing math for a scroll event that isn't going to happen in that direction.
The scroll handler:
$('#right-column').on('scroll', function (e) {
var $this = $(this),
$results = $("#results"),
scrollPosition = $this.scrollTop();
if (scrollPosition > ($this.data('scroll-position') || 0)) {
// Scrolling down
var threshold = $results.height() - $this.height() - $('.result:last-child').height();
if (scrollPosition > threshold) {
var $firstResult = $('.result:first-child');
$results.append($firstResult);
scrollPosition -= $firstResult.height();
$this.scrollTop(scrollPosition);
}
} else {
// Scrolling up
var threshold = $('.result:first-child').height();
if (scrollPosition < threshold) {
var $lastResult = $('.result:last-child');
$results.prepend($lastResult);
scrollPosition += $lastResult.height();
$this.scrollTop(scrollPosition);
}
}
$this.data('scroll-position', scrollPosition)
});
A complete working example:
$('#right-column').on('scroll', function (e) {
var $this = $(this),
$results = $("#results"),
scrollPosition = $this.scrollTop();
if (scrollPosition > ($this.data('scroll-position') || 0)) {
// Scrolling down
var threshold = $results.height() - $this.height() - $('.result:last-child').height();
if (scrollPosition > threshold) {
var $firstResult = $('.result:first-child');
$results.append($firstResult);
scrollPosition -= $firstResult.height();
$this.scrollTop(scrollPosition);
}
} else {
// Scrolling up
var threshold = $('.result:first-child').height();
if (scrollPosition < threshold) {
var $lastResult = $('.result:last-child');
$results.prepend($lastResult);
scrollPosition += $lastResult.height();
$this.scrollTop(scrollPosition);
}
}
$this.data('scroll-position', scrollPosition)
});
$('#results').on('click', '.result', function (e) {
$(this).find('.details').toggle();
});
$('#newNumber').on('input', function (e) {
var results = '';
for (var n = 1; n <= $(this).val(); n++) {
results +=
'<div class="result" id="result' + n + '">' +
' <div class="main">Result ' + n + '</div>' +
' <div class="details">Details for result ' + n + '</div>' +
'</div>';
}
$('#results').html(results);
});
body {
font-family: sans-serif;
}
h1 {
font: bold 2rem/1 Georgia, serif;
}
p {
line-height: 1.5;
margin-bottom: 1em;
}
label {
font-weight: bold;
margin-bottom: 1em;
}
.column {
box-sizing: border-box;
float: left;
width: 50%;
height: 100vh;
padding: 1em;
overflow: auto;
}
#right-column {
background-color: LemonChiffon;
}
.result {
padding: 1em;
cursor: pointer;
}
.result .main {
height: 2em;
font-weight: bold;
line-height: 2;
}
.result .details {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class=
"column" id="left-column">
<p>Existing DOM elements are moved to the top or bottom of the list depending on your scroll direction.</p>
<label>Change the number of results to display
<input id="newNumber" type="number" value="10" />
</div>
<div class=
"column" id="right-column">
<div id="results">
<div id="result1" class="result">
<div class="main">Result 1</div>
<div class="details">Details for result 1</div>
</div>
<div id="result2" class="result">
<div class="main">Result 2</div>
<div class="details">Details for result 2</div>
</div>
<div id="result3" class="result">
<div class="main">Result 3</div>
<div class="details">Details for result 3</div>
</div>
<div id="result4" class="result">
<div class="main">Result 4</div>
<div class="details">Details for result 4</div>
</div>
<div id="result5" class="result">
<div class="main">Result 5</div>
<div class="details">Details for result 5</div>
</div>
<div id="result6" class="result">
<div class="main">Result 6</div>
<div class="details">Details for result 6</div>
</div>
<div id="result7" class="result">
<div class="main">Result 7</div>
<div class="details">Details for result 7</div>
</div>
<div id="result8" class="result">
<div class="main">Result 8</div>
<div class="details">Details for result 8</div>
</div>
<div id="result9" class="result">
<div class="main">Result 9</div>
<div class="details">Details for result 9</div>
</div>
<div id="result10" class="result">
<div class="main">Result 10</div>
<div class="details">Details for result 10</div>
</div>
</div>
</div>
A complete working example on CodePen, if you prefer.
I recently took up a non-profit website as a project. I'm working with an existing website, so I'm having to work with a lot of the stuff already programmed, so all I have to do is create the design.
I made a diagram of basically what I can't figure out how to do:
I also made a JSFIDDLE of what is already there:http://jsfiddle.net/RmWu7/. I know I should of used a table for tabular data, but the programming is a bit weird, and I can't seem to figure out how to modify the php to work with a regular table, so I'm just going to keep the divs.
So two things:
I tried adding a position:fixed to .columns with the .last class, and an overflow-x:auto to the rest, but it completely messes up the layout.
How can I get the columns to be a fixed size instead of fluid, and have the last non-fixed column (before the columns with the .last class) to be bigger to fill up the table like in the diagram?
I'm trying to keep it mostly in CSS, but do I need to add jQuery as well?
Thanks for all help!
Ok I've totally change the codes as my previous version has problem on scrolling.
<div class="table">
<div class="wrap">
<div class="wrap2">
<div class='column'>
<div class='row top'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
</div>
<div class='column'>
<div class='row top'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
</div>
<div class='column'>
<div class='row top'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
</div>
</div>
</div>
<div class='column fixed-column'>
<div class='row top'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
<div class='row'>Test</div>
</div>
</div>
css:
.table{
overflow: hidden;
position: relative;
.wrap {
overflow-x: auto;
}
.wrap2 {
overflow: hidden;
zoom: 1;
}
.column{
float:left;
background:red;
width:200px;
.row{
padding:10px;
&.top{
background:green;
}
}
&.fixed-column {
position: absolute;
right: 0;
top: 0;
background:blue;
}
}
}
jQuery:
$(function() {
var scrollingWidth = $('.table').innerWidth();
var lastWidth = $('.table .wrap .column:last').outerWidth();
var innerWidth = 0;
$('.table .column').each(function() {
innerWidth += $(this).outerWidth();
});
var gap = scrollingWidth - innerWidth + lastWidth;
if(gap > lastWidth) {
$('.table .wrap .column:last').css('width', gap);
innerWidth += gap - lastWidth;
}
$('.table .wrap2').css('width', innerWidth);
});