Snap Scroll in depth with JavaScript/CSS - javascript

I need to go deep with Scroll Snap and your help.
I need to achieve 3 effects:
Able to be draggable
Able to scroll smoothly to an anchor
Able to Trigger a simple animation like changing color when content it's snapped
You can use CSS / JavaScript / jQuery / etc... to achieve the desired effects. Here's the snippet with no results so far:
a, span {
position: absolute
}
h1 {
font-size: 40px;
}
.child {
width: 400px;
height: 400px;
position: relative;
background-color: #F0F0F0;
display: inline-block;
margin-right: -4px;
border: 1px solid black;
}
.label {
width: 200px;
height: 200px;
border-radius: 25%;
background-color: white;
margin: 100px auto 0 auto;
}
.label > h1 {
font-size: 80px;
padding-left: calc(50% - 22px);
padding-top: calc(50% - 60px);
}
.container {
width: 402px;
height: 410px;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
margin: 10vh auto 0 auto;
}
#snap-scroll-container {
-webkit-scroll-snap-type: mandatory;
scroll-snap-type: mandatory;
-webkit-scroll-snap-points-x: repeat(100%);
scroll-snap-points-x: repeat(100%);
}
<div class="container" id="snap-scroll-container">
<div class="child">
<div class="label">
<h1>1</h1>
I must smooth scroll to 3!
</div>
</div>
<div class="child">
<div class="label">
<h1>2</h1>
<span>I must change color when snaps!</span>
</div>
</div>
<div id="3" class="child">
<div class="label">
<h1>3</h1>
<span>Scroll must be draggable too!</span>
</div>
</div>
</div>
Your help is really appreciated!

Related

Overlapping multiple div using CSS?

I'm trying to create a design using multiple divs using CSS.
I'm already written code for it but don't know what is the problem with my code as my left and right side div not aligning at vertically center and all the divs are not overlapped with main yellow centered div which is I'm unable to achieve.
Note: I tried this with z-index but did not get what I want.
Output I'm getting:
Output I want to achieve:
My code :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
</head>
<style>
.maind {
margin: 0px auto;
width: 90%;
padding: 10px;
height: 900px;
background-color: rgb(9, 252, 9);
position: relative;
}
.fdiv {
margin: auto;
width: 25%;
padding: 10px;
height: 100px;
background-color: rgb(10, 233, 222);
margin-top: 30px;
border: 2px solid red;
}
.sdiv {
width: 55%;
height: 600px;
background-color: #ffff00ec;
}
.tdiv {
margin: auto;
width: 25%;
padding: 10px;
height: 100px;
background-color: rgb(10, 233, 222);
border: 2px solid red;
}
p {
text-align: center;
}
.wrap {
display: flex;
flex-direction: row;
}
.wr1 {
width: 25%;
height: 100px;
background-color: rgb(10, 233, 222);
border: 2px solid red;
}
</style>
<body>
<div class="maind">
<div class="fdiv">
<p>Some content here...</p>
</div>
<div class="wrap">
<div class="wr1">
<p>Some content here..</p>
</div>
<div class="sdiv">
<p>Some content here..</p>
</div>
<div class="wr1">
Some content here...
</div>
</div>
<div class="tdiv">
<p>Some content here..</p>
</div>
</div>
</body>
</html>
Please somebody help me with the Source Code I tried almost all the related answer.
You can use Flexbox or Positioning.
Using Positioning makes it more flexible to add content to the holder element.
While Flexbox is more flexible when it's about adding and aligning boxes.
# Positioning
Description:
Create 4 elements to be the boxes.
Each .box has it's direction.
Example: <div class="box top"></div>.
Wrap all of them in div.boxes. This way you can separate the .boxes from the content (if there) in the holder,
<div class="boxes">
<div class="box top"></div>
<div class="box right"></div>
<div class="box left"></div>
<div class="box bottom"></div>
</div>
Style the the position of .wrapper so all the positioned absolute elements stays in the .wrapper.
.wrapper {position: relative;}
Finally, set the position of each box:
Example:
.box.top {
top: 0;
left: 50%;
transform: translateX(-50%);
margin-top: -40px;
}
Notes:
Don't use:
left property on .box.right.
top property on .box.bottom.
It won't set the negative margin which pushes them to edges.
In case content added to the holder (.wrapper), wrap the content in div.content and add inner space using padding. The value of padding in the code example is 40px, which it's related to the .boxes dimenstions.
The space (padding) is added to prevent overflow between content and .boxeses. And we can go further with styling the .boxes with overflow and z-index property.
For more about using negative maring and the boxes dimenstions:
Check for Notes in Flexbox
The Code:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrapper {
position: relative;
width: 600px;
height: 600px;
border: 1px solid;
margin: 50px auto;
}
.box {
position: absolute;
border: 1px solid;
background-color: red;
}
.box.top, .box.bottom {
width: 200px;
height: 80px;
}
.box.left, .box.right {
width: 80px;
height: 200px;
}
.box.top {
top: 0;
left: 50%;
transform: translateX(-50%);
margin-top: -40px;
}
.box.bottom {
bottom: 0;
left: 50%;
transform: translateX(-50%);
margin-bottom: -40px;
}
.box.left {
top: 50%;
left: 0;
transform: translateY(-50%);
margin-left: -40px;
}
.box.right {
right: 0;
top: 50%;
transform: translateY(-50%);
margin-right: -40px;
}
.content {
padding: 40px; /* check notes */
}
<div class="wrapper">
<div class="boxes">
<div class="box top"></div>
<div class="box right"></div>
<div class="box left"></div>
<div class="box bottom"></div>
</div>
<div class="content">
<h1>Hello World!</h1>
</div>
</div>
# Flexbox
Description:
Create 3 elements to hold the .boxes.
top: holding top box
center: holding left and right boxes
bottom: holding bottom box
In other words:
Each .box is nested (a child) in a div that has the class of the direction.
Example: <div class="top">BOX</div>.
Left and right are nested in center.
HTML:
<!-- top box -->
<div class="top">
<div class="box"></div>
</div>
<!-- left, right boxes -->
<div class="center">
<div class="left">
<div class="box"></div>
</div>
<div class="right">
<div class="box"></div>
</div>
</div>
<!-- bottom box -->
<div class="bottom">
<div class="box"></div>
</div>
Wrap all of them in a div.wrapper:
<div class="wrapper">
<!-- top box -->
<div class="top"></div>
<!-- left, right boxes -->
<div class="center"></div>
<!-- bottom box -->
<div class="bottom"></div>
</div>
The lines below will style the 3 elements and set them to their positions, .top will be centered (left right) and on top, .center will be centered from all the directions, .bottom is centered (left right) and at the bottom, by displaying the .wrapper children horizontally (flex-direction: column;) and centered (align-items: center;) with (space-between) them, using flex.
Check: A Complete Guide to Flexbox
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
Then we do something similar with the .center element, by displaying both of left and right next to each other, centered and space-between them.
(No flex-direction property in the declaration, since the default is in a row (vertically))
.wrapper .center {
width: 100%; /* Don't delete, check notes */
display: flex;
justify-content: space-between;
align-items: center;
}
And finally, with negative margin we move the boxes to the edges.
.top .box {
margin-top: -40px;
}
.bottom .box {
margin-bottom: -40px;
}
.center .left .box {
margin-left: -40px;
}
.center .right .box {
margin-right: -40px;
}
Notes:
The left and right boxes are (width: 80px), each, which means the margin should be -40px (80 / 2 = 40) to set on center.
left: margin-left: -40px
right: margin-right: -40px
Same for top and bottom, since the dimensions are flipped.
top: margin-top: -40px
bottom: margin-bottom: -40px
This way, all the boxes are gonna be centered at the edges.
By default, when displaying with flexbox, the parent(.center) will take the width of it's content/children (fitted)! which means, width: 40px * 2, since we have 2 boxes in there. Now to make sure that the space-between value works, we should "stretch" the .center element (parent) by styling it's width to 100% which allows to the boxes to have as much as space-between, then every box is gonna be on it's position.
.wrapper .center {
width: 100%; /* Don't delete, check notes */
}
The Code:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrapper {
border: 1px solid;
max-width: 600px;
min-height: 600px;
margin: 60px auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.box {
border: 1px solid;
background-color: red;
}
.wrapper .top .box,
.wrapper .bottom .box {
width: 200px;
height: 80px;
}
.wrapper .center .box {
width: 80px;
height: 200px;
}
.top .box {
margin-top: -40px;
}
.bottom .box {
margin-bottom:-40px;
}
.wrapper .center {
width: 100%; /* Don't delete, check notes */
display: flex;
justify-content: space-between;
align-items: center;
}
.center .left .box {
margin-left: -40px;
}
.center .right .box {
margin-right: -40px;
}
<div class="wrapper">
<div class="top">
<div class="box"></div>
</div>
<div class="center">
<div class="left">
<div class="box"></div>
</div>
<div class="right">
<div class="box"></div>
</div>
</div>
<div class="bottom">
<div class="box"></div>
</div>
</div>
EDIT:
As #anatolhiman mentioned in the comments:
but negative margins will create a problem by having the elements
overflowing right and left (especially on narrow screens).
A simple solution:
(same works for both examples)
wrap the HTML that we added before in another div, .container for example, and add spacing with CSS, either padding or margin works, depends on your situation.
So the question is...
Is it a space within the .container? --> padding.
Or outside of it? --> margin.
Give the .container a background-color, resize the window, and check both margin and padding to see the differences.
HTML - Update:
<div class="container">
<div class="wrapper">
</div>
</div>
CSS - Add:
/* outside space */
.container {margin: 50px;}
/* Or */
/* inside space */
.container {padding: 50px;}
You may have to edit the margin property in .wrapper for top bottom.
Extra space added (50px) to include spaces for the .boxes as well.
Remember: .wrapper{max-width: VALUE} is taking a place in this functionality, since it's max-width is X but it could be smaller. So if the property is width: and not max-width then it'll behave differently, and won't work as expected (fully responsive), unless we use #media query or JavaScript.
Maybe something like following snippet, with absolute positioning:
.maind {
margin: 0px auto;
width: 90%;
padding: 10px;
height: 900px;
background-color: rgb(9, 252, 9);
position: relative;
}
.fdiv {
margin: auto;
width: 25%;
padding: 10px;
height: 100px;
background-color: rgb(10, 233, 222);
margin-top: 30px;
border: 2px solid red;
position: absolute;
top: 0;
left: 35%;
z-index: 22;
}
.sdiv {
width: 80%;
position: absolute;
top: 10%;
left: 10%;
height: 600px;
background-color: #ffff00ec;
z-index: 12;
margin: 0 auto;
}
.tdiv {
margin: auto;
width: 25%;
padding: 10px;
height: 100px;
background-color: rgb(10, 233, 222);
border: 2px solid red;
position: absolute;
bottom: 20%;
left: 35%;
z-index: 22;
}
p {
text-align: center;
}
.wrap {
display: flex;
flex-direction: row;
}
.wr1 {
width: 25%;
height: 100px;
background-color: rgb(10, 233, 222);
border: 2px solid red;
position: absolute;
top: 35%;
left: 0;
z-index: 22;
}
.wr2 {
width: 25%;
height: 100px;
background-color: rgb(10, 233, 222);
border: 2px solid red;
position: absolute;
top: 35%;
right: 0;
z-index: 22;
}
<div class="maind">
<div class="fdiv">
<p>Top...</p>
</div>
<div class="wrap">
<div class="wr1">
<p>Left..</p>
</div>
<div class="sdiv">
<p>Somessss content here..</p>
</div>
<div class="wr2">
<p>Right...</p>
</div>
</div>
<div class="tdiv">
<p>Bottom..</p>
</div>
</div>

scrollTop returns 0

I have a fixed div in a vuejs app that i intend to use as a chat box. The div scrolls it's content within itself. I try to scroll to bottom automatically once chat box is open but it never works.
I have tried to assign scrollHeight to scrollTop but scrollTop always returns 0 even after assignment.
I have also emitted an event to the parent component that contains the scrollBar of the chat window to try to scroll but the problem is the same. scrollTop never gets assigned.
let msg = document.querySelector(".messanger .messanger-body");
msg.scrollTop = msg.scrollHeight;
console.log(msg.scrollTop);
console.log(msg.scrollHeight);
My problem is msg.scrollTop never gets assigned what msg.scrollHeight is. It remains 0.
<div class="messanger">
<div class="messanger-header text-center">
<div class="row h-100">
<div class="col-sm-12 my-auto">
<h2 class="ml-2 text-white">Chat</h2>
<div class="float-left">
<base-button size="sm" class="ml-1" type="primary" #click="returnToPrev">←</base-button>
</div>
<div class="float-right">
<base-button size="sm" class="mr-1" type="primary">Send message</base-button>
</div>
</div>
</div>
</div>
<div class="messanger-body">
<div>
<!-- child component -->
<message-thread :user="msgThread.user" #scrolltobtm="scrollViewToBtm"></message-thread>
</div>
</div>
</div>
I have a CSS like so for the parent component
.messanger {
background: white;
position: fixed;
top: 0;
width: 310px;
height: 70vh;
float: right;
right: 10px;
overflow-y: scroll;
overflow-x: hidden;
margin-top: 20vh;
border-top-left-radius: 20px;
border: 2px solid red;
}
.messanger .messanger-header {
position: fixed;
height: 60px !important;
width: 310px !important;
background: #25457a;
color: #ffffff;
z-index: 99999;
border-top-left-radius: 20px;
}
.messanger .messanger-body {
margin-top: 65px;
}
For my child component i have
<div class="message-history mt-2">
<div class="message-history-content">
<div class="text-center mb-4">
<span class="badge badge-info">Thread title : {{threadTitle}}</span>
</div>
<div v-for="(eachMessage, index) in messages" :key="index">
<div :class="messagePosition(eachMessage.added_by)[0]">
<!-- classes msg_container and msg_container_send are dynamically added here -->
<span>{{eachMessage.message}}</span>
</div>
</div>
</div>
<div class="message-input">
<form class="form m-1" #submit.prevent="sendMessage">
<textarea v-model="model.message" class="form-control"></textarea>
<div>
<button class="ni ni-send"></button>
</div>
</form>
</div>
</div>
Child component css
.msg_container {
margin-top: auto;
margin-left: 20%;
margin-right: 10px;
border-radius: 15px;
background-color: #82ccdd;
padding: 10px;
position: relative;
}
.msg_container_send {
margin-top: auto;
margin-right: 20%;
margin-left: 10px;
border-radius: 15px;
background-color: #25457a;
padding: 10px;
position: relative;
color: #ffffff;
}
.message-input {
position: fixed;
bottom: calc(100% - 90%);
background: #ffffff;
z-index: 99999;
}
.message-history {
overflow-x: hidden;
overflow-y: scroll;
margin-bottom: 40px;
}
.message-history .message-history-content {
overflow: scroll;
}
form {
display: flex;
width: 300px;
}
form button.ni.ni-send {
margin-top: 3px;
border-radius: 50%;
border: none;
height: 34px;
width: 34px;
background: #25457a;
color: #ffffff;
}
textarea {
flex-grow: 1;
resize: none;
border: 1px solid #25457a;
}
form button:focus {
outline: 0;
}
Thank you for help in advance.
I added overflow property to the .message-history class, it still doesn't work. I believe my mistake resides in my styles. I'm not much of a CSS person.
The chat window scrolls when the mouse is used to scroll though.
msg.scrollTop could stay with 0 value because of at least two things.
First .messanger-body don't have defined overflow property.
Second as it is initial phase content of .messanger-body have not enough content to make scroll appear on the right side of div.
Please check those options.

Adding content to div causes it to shift?

In the following code, I have a simple page setup, but as soon as I add something to the div with class page the whole main page div shifts downwards?
try adding <h1>hello</h1> to the div with class page.
what is the problem, the div should remain there and simply <h1>hello</h1> should be added!
code: https://jsfiddle.net/5sx0sj2q/
.container{
width: 100%;
background-color: #d5d5d5;
}
.sidebarcontainer{
width: 300PX;
height: 2000px;
display: inline-block;
box-sizing: border-box;
padding: 5px;
padding-right: 2px;
}
.innersidebarcontainer{
position: relative;
width: 100%;
height: 100%;
}
.sidebar{
width: 293px;
background-color: white;
height: 500px;
top: 1px;
position: absolute;
}
.mainpage{
width: calc(100% - 300px);
padding: 5px;
padding-left: 2px;
height: 2000px;
display: inline-block;
box-sizing: border-box;
}
.page{
width: 100%;
height: 100%;
background-color: white;
}
.footer{
height: 500px;
width: 100%;
margin: 0 auto;
background-color: #031003;
}
<div class="container">
<div class="sidebarcontainer">
<div class="innersidebarcontainer">
<div class="sidebar">
</div>
</div>
</div><!--
--><div class="mainpage">
<div class="page"></div>
</div>
</div>
<div class="footer"></div>
Yes there's a trick for that :
.mainpage{
vertical-align : top; // Add this
}
Also, change the H1 display property :
h1{
display : inline-block;
}
All the elements stay up where they should be. The joys of CSS.
Working Fiddle
Is normal, display: inline-block add a little space between elements (and you have no more space).
Use float left instead and your code works.

apply same jquery function to element present inside parent div

code jsFiddle
I applied jquery's click function to 'li#info' element. But when I click, it perform jquery to element of different parent also ('#theme div#info-overlay').
I want, whenever 'li#info' is clicked on the parent element('#theme') then it perform function to its child element only(div#info-overlay).
Like in the code, by clicking on 'Fe' it open overlay on both the block. But i want it to show overlay only to the block for which 'Fe'is clicked.
sorry, I am new in jquery.
I got your point. you just need to change one line of code
because both divs have same ids thats why both are appearing on click
and it's not a good practice to use same id multiple time on a single file.
it will make issue somewhere sometime.
i have change this line
$("div#info-overlay").toggle('100');
into this
$(this).parents('#theme').find("#info-overlay").toggle('100');
check this
JS Fiddle
use this to find div $(this).parents('#theme').find("#info overlay").toggle('100');
$(document).ready(function(){
$("div#theme").hover(function(){
$(".theme .header *").show();
$(".theme .header .overlay").hide();
},function(){
$(".theme .header *").hide();
});
$("li#info").click(function(){
$(".theme .header .overlay").hide();
$(this).parents('#theme').find("#info-overlay").toggle('100');
// $("div#info-overlay").toggle('100');
});
});
/*
theme block
*/
.theme{
width: 100%;
height: 250px;
background-color: #fff;
margin: 20px auto;
}
.theme .header{
width: 100%;
height: 200px;
position: relative;
background-color: #eee;
}
.theme .header *{
display: none;
}
.theme .header .overlay{
position: absolute;
background-color: #fff;
left: 60px;
top: 10px;
width: 83%;
height: 180px;
z-index: 80;
}
.theme .header .about{
position: absolute;
left: 10px;
top: 10px;
}
.theme .header .about li{
display: block;
height: 40px;
width: 40px;
border-radius: 50%;
background-color: #FED200;
opacity: .5;
color: #fff;
padding: 5px 10px;
margin: 5px 0;
}
.theme .footer{
width: 100%;
height: 50px;
padding: 0 20px;
}
.theme .footer .left{
width: 85%;
display: inline-block;
overflow-y:hidden;
height: 50px;
float: left;
padding: 10px 0;
}
#media screen and (min-width:620px) {
.theme{
width: 70%;
}
}
#media screen and (min-width:720px) {
.theme{
width: 49%;
display: inline-block;
}
}
#media screen and (min-width:920px) {
body .container.theme-holder {
width: 70%;
}
}
#media screen and (min-width:1024px) {
body .container.theme-holder {
width: 95%;
}
.theme{
width: 32%;
}
}
#media screen and (min-width:1200px) {
body .container.theme-holder {
width: 85%;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="theme" class="theme">
<div class="header">
<div class="about">
<li id="info">Fe</li>
</div>
<div id="info-overlay" class="overlay">
info
</div>
</div>
<div class="footer">
<div class="left">
<div class="name">
<p>Corporate sdfsfdsfdsfsd</p>
</div>
</div>
</div>
</div>
<div id="theme" class="theme">
<div class="header">
<div class="about">
<li id="info">Fe</li>
</div>
<div id="info-overlay" class="overlay">
info
</div>
</div>
<div class="footer">
<div class="left">
<div class="name">
<p>Corporate dfsasdfdsafs</p>
</div>
</div>
</div>
</div>

Problems with positioning and z-index

I'm trying to have the menu overlap content, but as of now it moves the content box away.
I've already tried the position: relative trick, but the problem doesn't seem to go away. The solution is probably something really obvious, but I need help finding it.
EDIT: Sorry, forgot to add, the box will also be resizable() so I'm trying to avoid absolute positioning.
EDIT2: nevermind, right:5px fixes that problem
JSFiddle
HTML
<div class="box">
<div class="top">
<div class="icon"></div>
<div class="menubox">
<ul class="menu">
<li>Menu Option 1
</li>
<li>Menu Option 2
</li>
</ul>
</div>
</div>
<div class="content">
<p>content goes here</p>
</div>
<div class="content">
<p>content goes here</p>
</div>
</div>
CSS
.box {
width: 400px;
height: 200px;
margin: 5px;
float: left;
background: LightGray;
border: 1px solid DarkGray;
overflow: hidden;
}
.top {
width: 100%;
height: 25px;
background: lightblue;
}
.icon {
float: right;
background: red;
height: 15px;
width: 15px;
margin: 5px;
}
.menubox {
float: right;
background: yellow;
position: relative;
z-index:100;
width: 150px;
}
.content {
width: 180px;
height: 165px;
margin: 0px 10px 47px;
float: left;
position: relative;
z-index: 0;
display: block;
background:DarkGray;
}
li {
list-style-type: none;
text-decoration: none;
}
ul {
margin:none;
padding:none;
}
JS/jQuery
$('.icon').mouseover(function () {
$(".menu").show();
}); //toggle menu on hover
$(".menu").mouseleave(function () {
$(this).hide();
});
use position: absolute?
fiddle
.menubox {
float: right;
background: yellow;
position: relative;
z-index:100;
width: 150px;
top: 25px;
right: 5px;
position: absolute;
}
.box {
width: 400px;
height: 200px;
margin: 5px;
float: left;
background: LightGray;
border: 1px solid DarkGray;
overflow: hidden;
position: relative; /* add this */
}
Edit: better position
The yellow menubox needs to be positioned absolutely so it does not interfere with the flow of the document (take up space).
Give it a position:absolute;
Furthermore, the .box element needs to have a position:relative so the menu is positioned relative to that box.
Updated your fiddle for you:
http://jsfiddle.net/CcVnL/11/
Check the below link i have updated your code.
"jsfiddle.net/CcVnL/9/"

Categories