Vertically Draggable Division of Two Areas - javascript

I want to make a vertically draggable division of two areas like the following.
I just want to modify a online example of draggable divs to be what I want. Finally, I got this. Can someone give me some hints to modify it?
JSFiddle Link : https://jsfiddle.net/casperhongkong/omekvtka/14/
HTML
<div class="container">
<div class="area1">
Area 1
</div>
<div class="drag">
</div>
<div class="area2">
Area 2
</div>
</div>
CSS
.container {
position: fixed;
top: 51px;
right: 0px;
bottom: 0px;
left: 0px;
background-color: #272822;
border: 1px solid #222;
// margin: 0 auto;
//display: inline-block;
}
.area1 {
position: absolute;
height: 100%;
width: 30%;
background-color: #ddd;
display: inline-block;
}
.drag {
position: fixed;
width: 5px;
height: 100%;
background-color: #444;
display: inline-block;
}
.area2 {
position: absolute;
right: 0;
height: 100%;
width: 30%;
background-color: #ddd;
display: inline-block;
}
JavaScript
$(document).ready(function() {
$('.drag').on('mousedown', function(e) {
var $area1 = $('.area1'),
$area2 = $('.area2'),
startWidth_a1 = $area1.width(),
startWidth_a2 = $area2.width(),
pX = e.pageX;
$(document).on('mouseup', function(e) {
$(document).off('mouseup').off('mousemove');
});
$(document).on('mousemove', function(me) {
var mx = (me.pageX - pX);
$area1.css({
width: startWidth_a1 - mx;
});
$area2.css({
//left: mx / 2,
width: startWidth_a2 - mx,
//top: my
});
});
});
});

For javascript, I would recommend checking out a library, as this is slitghtly more complicated than just a few lines. #fauxserious gave Split.js as a fantastic example.
This is possible in pure HTML/CSS, though slightly limited, as discussed here.
HTML:
<div class="split-view">
<div class="resize-x panel" style="width: 216px;">
Panel A
</div>
<div class="panel">
Panel B
</div>
</div>
CSS:
/* Panels: */
.panel{
padding: 1em;
border-width: 6px;
border-style: solid;
height: 4em;
}
/* Resizing */
.resize-x {
resize: horizontal;
overflow: auto;
}
/* Split View */
.split-view {
margin: 1em 0;
width: 100%;
clear: both;
display: table;
}
.split-view .panel {
display: table-cell;
}

Based on #afischer's table-cell solution, here is an alternative one.
I have had to put accordions within the left side panel.
The sticky headers of the accordions require overflow to be visible,
while resize requires overflow to be anything but visible:
https://caniuse.com/#feat=css-sticky.
In the same time, I didn't need anything to place into the right side panel.
Thus, an overcome was employing resize on the right panel, and rotating by 180 deg to get the dragable side to the middle, as well as this way the dragable corner relocated to the top (visible without scrolling).
Plus some highlight has been added to the dragable corner.
/* Panels: */
.panel{
padding: 1em;
border-width: 6px;
border-style: solid;
height: 4em;
}
/* Resizing */
.resize-x {
resize: horizontal;
overflow: auto;
transform: rotate(180deg);
border-right: solid gray 1px;
}
/* Split View */
.split-view {
margin: 1em 0;
width: 100%;
clear: both;
display: table;
}
.split-view .panel {
display: table-cell;
}
.resize-x::-webkit-resizer {
border-width: 8px;
border-style: solid;
border-color: transparent orangered orangered transparent;
}
<div class="split-view">
<div
class="panel"
style="width: 216px;">
Panel A
</div>
<div class="panel resize-x">
Panel B
</div>
</div>
Unfortunately there are two disappointing thing with the above:
Firefox cannot handle the combination of table-cell and resize
Only a corner of the grabber is responsive, which can even be scrolled out easily
Here is an other solution which also takes the above two problems into account
without resize CSS property
and with full height responsive grabber
It's a combination of a flexbox and an input:range slider.
The trick is that the pointer-event CSS property can be different
on the slider's background
and on its grabber.
The slider covers the entire view. The background of the slider is transparent for the events too (pointer-events: none), while the dragbar itself catches the events (pointer-events: auto).
It requires minor Javascript and because I've implemented the production version in Nuxt.js, I use Vue.js here, instead of vanilla JS.
new Vue({
el: '#vue',
data: {
windowWidth: null,
splitWidth: null,
},
mounted() {
this.windowWidth = window.innerWidth;
// For arbitrary initial position:
this.splitWidth = this.windowWidth * 2/3;
},
computed: {
flexRatio() {
return this.splitWidth / this.windowWidth;
}
}
})
body {
margin:0;
}
main {
display: flex;
width: 100%;
height: 100vh;
}
article {
display: flex;
}
section {
width: 100%;
height: 100%;
text-align: justify;
padding: 20px;
}
.section-left {
background-color: darkseagreen;
}
.section-right {
background-color: orangered;
}
#split-grabber {
pointer-events: none;
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
-webkit-appearance: none;
/* Safari allows dragging behind scroll bar.
We fix it by shrinking its width on the right side via both
its range value :max="windowWidth - 12"
and its width (CSS) width: calc(100% - 12px)
...synchronously */
width: calc(100% - 12px);
height: 100vh;
background: transparent;
outline: none;
margin: 0;
}
#split-grabber::-webkit-slider-thumb {
z-index: 1;
pointer-events: auto;
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 100vh;
background: lightgray;
box-shadow: 1px 2px 2px 0px gray;
cursor: col-resize;
}
#split-grabber::-moz-range-thumb {
z-index: 1;
pointer-events: auto;
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 100vh;
background: lightgray;
box-shadow: 1px 2px 2px 0px gray;
cursor: col-resize;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="vue">
<!-- Safari allows dragging behind scroll bar
We fix it by shrinking its width on the right side via both
its range value :max="windowWidth - 12"
and its width (CSS) width: calc(100% - 12px)
...synchronously -->
<input
id="split-grabber"
type="range"
v-model="splitWidth"
:max="windowWidth - 12"
>
<article
class="article"
:style="{'flex': flexRatio}"
>
<section
class="section section-left">
splitWidth:{{ splitWidth }}px<br>
“There was a rich man who always dressed in the finest clothes and lived in luxury every day.
And a very poor man named Lazarus, whose body was covered with sores, was laid at the rich man’s gate.
He wanted to eat only the small pieces of food that fell from the rich man’s table. And the dogs would come and lick his sores.
Later, Lazarus died, and the angels carried him to the arms of Abraham. The rich man died, too, and was buried.
In the place of the dead, he was in much pain. The rich man saw Abraham far away with Lazarus at his side.
He called, ‘Father Abraham, have mercy on me! Send Lazarus to dip his finger in water and cool my tongue, because I am suffering in this fire!’
</section>
</article>
<article
class="article"
:style="{'flex': 1-flexRatio}"
>
<section class="section section-right">
But Abraham said, ‘Child, remember when you were alive you had the good things in life, but bad things happened to Lazarus. Now he is comforted here, and you are suffering.
Besides, there is a big pit between you and us, so no one can cross over to you, and no one can leave there and come here.’
The rich man said, ‘Father, then please send Lazarus to my father’s house.
I have five brothers, and Lazarus could warn them so that they will not come to this place of pain.’
But Abraham said, ‘They have the law of Moses and the writings of the prophets; let them learn from them.’
The rich man said, ‘No, father Abraham! If someone goes to them from the dead, they would believe and change their hearts and lives.’
But Abraham said to him, ‘If they will not listen to Moses and the prophets, they will not listen to someone who comes back from the dead.’”
</section>
</article>
</main>

Related

How do I create flexible div containers that marry float behavior with dynamic widths and heights?

I'm trying to create the below situation where the content_container's width reaches the right side of the screen and automatically scales depending on whether the expandable pane is collapsed or not. If I put width: 100% on .content_container it goes past the width of the screen, creating an unnecessary scroll bar as well as shifts to being under the expandable pane. Also you can see that the expandable_pane's height does not reach the full extent of the parent, but the content_container's does.
There is obviously something I'm not understanding on a fundamental level as I will admit that my grasp of various display types and behaviors is not solid and I'm still learning. Any help would be appreciated.
$(document).ready(function(){
$("#expandable_pane").click(function(){
if(this.className.search("collapsed") != -1){
this.className = this.className.replace("collapsed", "extended");
} else {
this.className = this.className.replace("extended", "collapsed");
}
})
})
.expandable_pane{
float: left;
box-shadow: 1px 1px 10px 1px rgb(98,98,98);
overflow: hidden;
white-space: nowrap;
height: 100%;
padding: 2px;
transition: width .5s;
}
.expandable_pane.collapsed {
width: 10px;
}
.expandable_pane.extended {
width: 500px;
}
.flex_container {
height: 300px;
}
.content_container{
float: left;
padding-left: 10px;
height: 100%;
}
.content_pane {
padding: 10px;
box-shadow: 1px 1px 10px 1px rgb(98,98,98);
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex_container">
<div class="expandable_pane collapsed" id="expandable_pane">
Menu Icons/Links would go here.
</div>
<div class="content_container">
<div class="content_pane">
Information for page here.
</div>
</div>
</div>
You aren't that far off with your code. First of all, your .flex_container class is missing display: flex. Secondly, if you want your container to take up the remainder of the space, it needs to be able to flex. If you give the container flex: 1 100px, which is a shorthand property, it tells the container to flex-grow: 1 with a flex-basis of 100px. With flexbox, you no longer need float: left in this scenario.
Try playing around with the values to get a better grasp of how flexbox can work and I also recommend reading the MDN articles on the property. MDN Flex
$(document).ready(function(){
$("#expandable_pane").click(function(){
if(this.className.search("collapsed") != -1){
this.className = this.className.replace("collapsed", "extended");
} else {
this.className = this.className.replace("extended", "collapsed");
}
})
})
.expandable_pane{
box-shadow: 1px 1px 10px 1px rgb(98,98,98);
overflow: hidden;
white-space: nowrap;
height: 100%;
padding: 2px;
transition: width .5s;
}
.expandable_pane.collapsed {
width: 10px;
}
.expandable_pane.extended {
width: 500px;
}
.flex_container {
display: flex;
height: 300px;
}
.content_container{
padding-left: 10px;
flex: 1 100px;
height: 100%;
}
.content_pane {
padding: 10px;
box-shadow: 1px 1px 10px 1px rgb(98,98,98);
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex_container">
<div class="expandable_pane collapsed" id="expandable_pane">
Menu Icons/Links would go here.
</div>
<div class="content_container">
<div class="content_pane">
Information for page here.
</div>
</div>
</div>

Center the focused item in horizontal scroll

I have created a horizontal scroll container with <HTML/> and CSS:
body {
background-color: #212121;
}
.scroll_container {
height: 100px;
width: 400px;
display: flex;
align-items: center;
overflow-y: hidden;
width: 100%;
height: 20%;
}
.scroll_container_sub {
height: 100px;
min-width: 230px;
float: none;
display: inline-block;
zoom: 1;
margin: 10px;
border: solid 1px transparent;
border-radius: 15px;
background-color: #fff;
}
<div class="scroll_container">
<div class="scroll_container_sub"></div>
<div class="scroll_container_sub"></div>
<div class="scroll_container_sub"></div>
</div>
What I try:
Is it possible that every time one item (scroll_container_sub) is centered in the scroll_container? Especially for mobile use, this is very good.
EXAMPLE:
After the scroll the middle item gets centered horizontally:
(image: mobile view)
That means that things like this should not exist:
Because none of the containers are centered. When I look at a scroll position like this the scroll view should center one of the containers.
For hopefully more detail: :)
In the following link, you see what I try to achieve. Look only at the few seconds in the beginning.
The cards are centered every time after the user swiped. Exactly what I try to achieve:
https://www.youtube.com/watch?v=UsXv6VRqZKs Do you need a live example? No Problem. In the Google Play Store, you find them. For example this swiper:
~filip
2022 edit: unless you need to support old browsers, scroll-margin is now the way to go.
JS implementation and theory follows:
The general formula is as following - you find your element of interest, find its middle point (x + width / 2), then subtract half of container's width from that:
window.addEventListener("load", function(e) {
var container = document.querySelector(".scroll_container");
var middle = container.children[Math.floor((container.children.length - 1) / 2)];
container.scrollLeft = middle.offsetLeft +
middle.offsetWidth / 2 - container.offsetWidth / 2;
});
body {
background-color: #212121;
}
.scroll_container {
height: 100px;
width: 400px;
display: flex;
align-items: center;
overflow-y: hidden;
position: relative;
width: 100%;
height: 20%;
}
.scroll_container_sub {
height: 100px;
min-width: 230px;
float: none;
display: inline-block;
zoom: 1;
margin: 10px;
border: solid 1px transparent;
border-radius: 15px;
background-color: #fff;
}
<div class="scroll_container">
<div class="scroll_container_sub"></div>
<div class="scroll_container_sub"></div>
<div class="scroll_container_sub"></div>
</div>
If you want to dynamically apply this effect, you would want to wait until the user is done scrolling, calculate the new scroll destination, and ease towards that over time.

Fixed aspect ratio box with letter and pillarboxing between header and footer

Running the following code snippet will provide a framework for what I am visually hoping to accomplish, with some concessions made in the CSS that I'd like to remove:
body {
height: 100vh;
margin: 0;
}
.container>* {
height: 100%;
width: 100%;
flex: 0 0 50px;
}
.container {
width: 100%;
height: 100%;
background-color: black;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.header {
background-color: red;
}
.content {
background-color: blue;
flex: 1;
position: relative;
}
.footer {
margin-top: auto;
background-color: yellow;
}
.fixedRatio {
height: 56.25vw;
max-height: calc(100vh - 100px);
width: calc((100vh - 100px) * (1/0.5625));
;
max-width: 100vw;
background-color: rgba(0, 0, 0, 0.5);
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
<div class="container">
<div class="header"></div>
<div class="content">
<div class="fixedRatio"></div>
</div>
<div class="footer"></div>
</div>
Included are a header and footer of arbitrary height and a fixed aspect ratio box centered vertically and horizontally between them. I'd like it to letter- and pillar-box as the page is resized, and respond to increases/decreases in header height.
As it stands, the code accomplishes many of these goals but falls short in that it requires that the heights of the header and footer be included in the CSS for the fixed aspect ratio box. This limits my ability to freely manipulate the size of the header, or let it grow arbitrarily as a function of content (at least to the extent I am not using JavaScript).
I've managed to make this work successfully for the case of letter-boxing (top and bottom black bars) by leveraging the fact that the content is full-width. As a result, I can use 100vw / 56.25vw (in the case of 16:9) for the width/height and achieve the desired result. Unfortunately, when moving the content around to pillar-box, this obviously falls apart.
I've more or less resigned myself to needing JavaScript to - at the very least - toggle a class based on the dimensions of the inner content box to determine whether letter or pillar boxing is appropriate. However, it became very clear very quickly that setting width as a function of height is not trivial.
I was fortunate to come across this post, where a solution leveraging a 1x1 pixel is used to set width as a function of height.
I was able to successfully make this work for the pillar-boxing case in both Chrome and Safari, but not Firefox (IE11 and Edge not yet tested, but coverage is desired... pray for me). I'd like to get recent versions of Chrome/Safari/Firefox covered, as well as I11/Edge if possible.
The solution for Chrome/Safari is as follows:
body {
height: 100vh;
margin: 0;
}
.header,
.footer {
height: 100%;
width: 100%;
}
.container>* {
flex: 0 0 50px;
}
.container {
width: 100%;
height: 100%;
background-color: black;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.header {
background-color: red;
}
img {
display: block;
height: 100%;
background: orange;
}
.content {
background-color: blue;
flex: 1;
position: relative;
overflow: hidden;
height: 100%;
display: inline-block;
left: 50%;
transform: translateX(-50%);
}
.footer {
margin-top: auto;
background-color: yellow;
}
.fixedRatio {
background-color: purple;
position: absolute;
left: 0;
top: 0;
right: 0;
margin: auto;
bottom: 0;
}
<div class="container">
<div class="header"></div>
<div class="content">
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" />
<div class="fixedRatio"></div>
</div>
<div class="footer"></div>
</div>
There are a few things to consider. I am comfortable with fixing the height of the footer. This constraint may prove valuable, but I've been unable to yield anything from it yet. I am also comfortable with radical alterations to the included markup, supposing it enables the desired behavior.
The end-purpose of this would be to maintain fixed aspect ratio content between this flexible header, static footer, and overlay content upon it.
I am well aware that I could run some JavaScript and set these heights manually with great success, but I am coming at this from a position largely based in intellectual curiosity. If you, too, are curious, perhaps you can lend a hand in exploring :)
Thank you!

align texts or images in Bootstrap carousel

I use Bootstrap 3.3.4 and I want to know which way is better to align texts or items in carousel.
here is a exemple from a slider. How can I align text like this and stay at any screen resolution at the same place. I use top: x, right: x but every time when I resize the window, text climb above and not stay at middle anymore.
CSS for align
.carousel-caption {
position: absolute;
right: 15%;
bottom: 40%;
left: 15%;
z-index: 10;
padding-top: 20px;
padding-bottom: 20px;
color: #fff;
text-align: center;
text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
Just basic bootstrap slider. But If I use bottom 40% for exemple to rise text at middle of the page works. But if I use smaller displays the text rise and stay almost on top.
In this exemple text stay fixed on every device.
<div class="wrap">
<div class="display-table">
<div class="display-cell">
<h1>Title in here</h1>
</div>
</div>
</div>
<style>
.wrap {
width: 100%;
height: 400px;
}
.display-table {
width: 100%;
height: 100%;
display: table;
}
.display-cell {
width: 100%;
height: 100%;
display: table-cell;
vertical-align: middle;
}
</style>
This allows fixed vertical alignment and should work cross browser. Just note the fixed height applied to .wrap must be present for the children to inherit 100% height!
Hope this helps :)
Hope, Try this demo that centers text vertically in the Bootstrap carousel.
Here is the Fiddle.
All I do here is give the div a height that contains the text and then position it with this css...
.vcenter {
position: absolute;
height:100px;
width:100%;
top:50%;
bottom:50%;
margin-top: -50px;
margin-bottom: -50px;
}

border-radius + overflow:hidden when animating with jQuery

Check this jsFiddle.
The orange bar is serving as a progress bar where the value under the circle is how high the progress bar should be.
Any idea why the overflow:hidden; is beeing disregarded and how do one solve this problem? Oblviously nothing should go outside the circle.
Also is there a better solution for this?
Modified your fiddle a little bit. Here is the link
Modifications:
Changed .outerContainer css to display:block from display:table and addedmargin-top:30px to p css
Check if this works for you.
position: absolute and overflow: hidden don't appear to be playing nicely with display: table/table-cell. Removing the table stuff you had in there to vertically center the text fixes the problem. In Firefox, at least.
I think it's the browser thing...
This is the CSS3 version...
.progressBar {
display: block;
width: 100%;
height: 0;
position: absolute;
bottom: 0;
left: 0;
background: #ec6730;
transition: height 1s;
}
.innerContainer:hover > .progressBar {
height: 300px;
}
http://jsfiddle.net/ZyhgT/2/
It no longer flashing 'cause browser handle the job (not js loop animation...). But still it shows the edge on animation finish!!! This could be the browser things... Could be a bug...
This is not related to jQuery or any javascript. In fact, if you delete all your javascript and manipulate the height of your .progressBar using css on li:hover, you will notice the bug anyway.
It appears to be a browser issue as reported on: https://code.google.com/p/chromium/issues/detail?id=157218
As a workaround try adding an imperceptible css transform to the mask element:
.outerContainer {
-webkit-transform: rotate(0.000001deg);
}
You just need to change your .outerContainer class and it works just fine!
.outerContainer {
position: relative;
display: block;
height: 96px;
width: 96px;
overflow: hidden;
background: #fff;
border: 2px solid #fff;
-webkit-border-radius: 50px;
border-radius: 50px;
}
Put the level class inside the outerContainer div and style the span inside the level class to be relatively positioned. In the JavaScript, to calculate the level, divide by 10 instead of 100 for the perfect circular hover effect.
Here is a fiddle.
HTML
<div class="outerContainer">
<div class="innerContainer">
<p>Circle 3</p>
<span class="progressBar"></span>
</div>
<div class="level"><span>75</span>
</div>
</div>
CSS
body {
background: blue;
}
#circles {
text-align: center;
margin: 100px 0;
}
li {
display: inline-block;
margin: 0 10px;
position: relative;
}
.outerContainer {
position: relative;
display: block;
height: 96px;
width: 96px;
overflow: hidden;
background: #fff;
border: 2px solid #fff;
-webkit-border-radius: 50px;
border-radius: 50px;
}
.innerContainer {
display: table-cell;
vertical-align: middle;
width: 100%;
margin: 0 auto;
text-align: center;
}
p {
color: #000;
width: 96px;
position: relative;
z-index: 2;
}
.progressBar {
display: block;
width: 100%;
height: 0;
position: absolute;
bottom: 0;
left: 0;
background: #ec6730;
}
.level span{
position:relative;
}
JS
$(function() {
$("#circles li").hover(function(){
var thisElement = $(this);
var level = $(this).find(".level").text();
var elementHeight = $(this).find(".outerContainer").height();
level = (level/10)*elementHeight;
$(thisElement).find(".progressBar").stop().animate({
height: level
}, 300);
}, function() {
var thisElement = $(this);
$(".progressBar").stop().animate({
height: 0
}, 300);
});
});
display: table doesn't work that good with CSS positioning;
you should avoid using that, and find some other way to vertically center your labels.
If your circles have a known height, like your code seems to indicate (height:96px ecc), then just use a fixed top position for an absolutely positioned <p> element:
http://jsfiddle.net/ZyhgT/5/
Note that you don't even need jQuery for this, it is all achievable with just CSS3 (unless you are targeting old browsers)

Categories