Seamless onClick animated <div>s - javascript

I'm creating a portfolio website for a photographer. The idea is to have 3 main sections, animated on click. When you click on any of those it will take about 80% space revealing itself and pushing others to the side(s). They will be packed with content like albums, text, images etc. It has to be seamless transitions between those 3 and any clickable item inside. that's the question itself: how do i achieve that, i suppose it has to be JS, maybe there is ready framework for that feature? Check out pic below for better understanding

Use this as the basis to fit it to you use-case. Works on hover on any section.
Snippet:
* { box-sizing: border-box; margin: 0; padding: 0; font-family: sans-serif; }
.parent {
width: 100vw; height: 120px;
display: flex;
flex-direction: columns;
}
.parent > div {
background-color: #ddd; text-align: center; padding: 12px 8px;
flex: 1 1 10%;
transition: all 500ms;
}
.parent > div:hover {
flex: 1 1 80%;
}
.parent > div:first-child { background-color: #d33; }
.parent > div:last-child { background-color: #33d; }
<div class="parent">
<div>1</div>
<div>2</div>
<div>3</div>
</div>

Related

HTML - Fitting images in multiple rows to fit viewport

I am developing a website, in which I display N amount of images. A good example of how I would like to display them is how DeviantArt does it. Images are shown in rows in such a way that it fills the width of the current viewport and does not deform any images.
My attempt was the following:
#CSS
.item {
display: inline-block;
vertical-align: top;
position: relative;
overflow: hidden;
padding: 0.5em;
background: lightcoral;
border: black solid 1px;
}
.item img{
max-height: 200px;
object-fit: scale-down;
}
HTML
<div style="display: block; width: 100%">
<!-- A vue directive, used in this example to render this element n amount of times per images -->
<div class="item" v-for="(i, index) in images" :key="index">
<img :src="i.url">
<div style="display: flex; flex-direction: column;">
<div>{{i.title}}</div>
<div>By User1234</div>
</div>
</div>
</div>
Which results in the following:
As you can see, there are gaps left at the end of each row. Id like for each row to be able to fit all possible images so that the grid fits the viewport, like this:
Im very interested to know how I can achieve this, either by using pure HTML / CSS or Javascript if needed.
You probably want to use flexbox with flex-grow.
CSS-Tricks has a great article on this here: https://css-tricks.com/piecing-together-approaches-for-a-css-masonry-layout/
Here's a codepen from the article:
codepen
body {
margin: 0;
padding: 1rem;
}
.masonry-with-columns {
display: flex;
flex-wrap: wrap;
div {
height: 150px;
line-height: 150px;
background: #EC985A;
color: white;
margin: 0 1rem 1rem 0;
text-align: center;
font-family: system-ui;
font-weight: 900;
font-size: 2rem;
flex: 1 0 auto;
}
#for $i from 1 through 36 {
div:nth-child(#{$i}) {
$h: (random(400) + 70) + px;
width: $h;
}
}
}

How to set an element so that it uses the remaining height of the parent element whilist having other 2 dynamic elements on it?

So let me elaborate a little bit more in the title, I have this fixed container that has 3 elements inside of it, all 3 of them should change dynamically since the first and the second one have preference over the third one I need this one to take the rest of the containers space.
I've tried using flexbox but I doesn't seems to have a solution for this particular problem I have, (Or maybe I just don't know how to use it)
And I also tried using JS to get the h1 and p height and then substract it from the container with this little function
document.getElementById('DescTitle').clientHeight;
but I can't make it work...
<div class="Container" id="DescContainer">
<h1 id="DescTitle">Title</h1>
<p id="DescParagraph">A longer text</p>
<div Class="Interior-Container">
</div>
</div>
body {
margin: 0;
text-align: center;
}
.Container {
height: 100vh;
color: black;
}
.Container h1 {
font-size: 8vh;
margin-left: 3vw;
margin-right: 3vw;
}
.Container p {
font-size: 4vh;
margin-left: 3vw;
margin-right: 3vw;
}
.Interior-Container {
background-color: black; /*I'm only using this for testing porpuses*/
}
So pretty much I just want "Interior-Container" to take the rest of the view height that the title and paragraph left and for this solution to work even if you change the window size, cause I'm planning on putting even more dynamic objects based of the size of this last div...
You can achieve this with flex, but therefor you need to change your CSS a bit.
You need to set diplay: flex;and flex-direction: column; at .Container class.
And for the elements inside your container you can use min-height if you want to make all elements the same height if the content fits. For the third element in your container you set flex: 1 to make it flexible.
https://www.w3.org/TR/css-flexbox-1/#flex-common
This CSS should do the job if I read your question correctly:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
text-align: center;
}
.Container {
height: 100vh;
color: black;
display: flex;
flex-direction: column;
}
.Container h1 {
background-color: blue;
min-height: 33%;
}
.Container p {
background-color: orange;
min-height: 33%;
}
.Interior-Container {
flex: 1;
background-color: black;
}
<div class="Container" id="DescContainer">
<h1 id="DescTitle">
Title<br />
Title
</h1>
<p id="DescParagraph">
A longer text<br />
A longer text<br />
A longer text<br />
A longer text<br />
A longer text<br />
</p>
<div Class="Interior-Container">
</div>
</div>

Increase the height of all elements when one element increases (equal height columns)

I want all 100% height elements to expand when the size of the body expands.
In the example pressing the button will add a red div - the two columns adjacent should stretch to account for this. In the end all columns should reach the bottom completely, one with blue then red, the other two just blue.
I'm looking into flex, and it doesn't seem like this would work, but any suggestions are appreciated.
In any case best solution is CSS, but if this is impossible pure JS is also fine.
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
html, body{
height: 100%;
}
span {
display: inline-block;
background-color: blue;
width: 30px;
height: 100%;
vertical-align: top;
}
div {
background-color: red;
width: 30px;
height: 30px;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
This is what I expect the frame to look like at the bottom after button is pressed and scrolled down:
EDIT
I changed the snippet so the button appends the div to an existing child and causes overflow, as per the comments below suggest.
An initial setting of a flex container is align-items: stretch. This means that flex items will expand to cover the full length of the container along the cross axis.
In a container with flex-direction: row, the cross axis is vertical, so items will expand to full height.
In your demo code, the divs (red) are being added as children of a span column (blue). These divs are being added to the end, forcing the column to grow.
In a row-direction flex container, with no heights specified that would override align-items: stretch, the other columns will follow suit.
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
body {
display: flex;
min-height: 100vh;
}
body > span {
width: 30px;
margin-right: 5px;
background-color: blue;
display: flex;
flex-direction: column;
}
body > span:first-child span {
flex: 0 0 100vh;
}
div {
background-color: red;
width: 30px;
height: 30px;
}
button {
margin-bottom: auto;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
You should use Flexbox twice, once in the outer container, and once in the container containing the appended child elements.
Here is your modified code:
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
html, body{
height: 100%;
/* new */
display: flex;
}
/* new */
body > span{margin-right: 4px;}
span {
/*display: inline-block;*/
background-color: blue;
width: 30px;
height: 100%;
vertical-align: top;
/* new */
display: flex;
flex-flow: column;
align-items: flex-end;
}
div {
background-color: red;
width: 30px;
height: 30px;
/* new */
flex: 1 0 auto;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>

Show one element if another is above a certain height

I have a following HTML:
<span class="day-number">{{day-number}}</span>
<div class="event-box">
<div class="event-container">
</div>
<div class="more-events">more ...</div>
</div>
Event-container is filled with an unknown number of .event elements like the following:
<div class="event">{{event-name}}</div>
I want to show or hide the .more element based on if the .event-container has a height of over 76px (equal to the height of four .event elements stacked).
The styling for the above elements:
.event {
text-align: left;
font-size: .85em;
line-height: 1.3;
border-radius: 3px;
border: 1px solid #3a87ad;
background-color: #3a87ad;
font-weight: normal;
color: whitesmoke;
padding: 0 1px;
overflow: hidden;
margin-bottom: 2px;
cursor: pointer;
}
.event-box {
max-height: 76px;
overflow: hidden;
position:relative;
}
.event-box .more-events {
height: 10px;
position: absolute;
right: 0;
bottom: 10px;
display: none;
z-index: 5;
}
No styling for .event-container
I can do what I want with Javascript (jQuery):
$(".event-box").each(function(){
var $this = $(this);
if($this.children(".event-container").height() > 76){
$this.children(".more-events").css("display", "block");
} else {
$this.children(".more-events").css("display", "");
}
});
And run that every time a make a change, but I'd rather do it with CSS.
Is this possible? Maybe with pseudo elements or media queries or something?
JSFIDDLE: http://jsfiddle.net/pitaj/LjLxuhx2/
If changing the markup is acceptable there is a possibility to achieve a somewhat similarly looking page without using JavaScript to show or hide, here is the Fiddle
I have removed <div class="more-events">more ...</div> line and made elements of event class to get hide when it is necessary I also made them to appear when hovering over more ... .
The CSS I have added:
.event:nth-child(n){
display: none;
}
.event:nth-child(1),.event:nth-child(2),.event:nth-child(3),.event:nth-child(4){
display: block;
}
.event:nth-child(5){
text-indent: -9999px;
position: relative;
display: block;
color: black;
border: none;
background-color: #FFF;
}
.event:nth-child(5)::before{
position: absolute;
text-indent: 0px;
content: "more ...";
display: block;
}
.event:nth-child(5):hover{
position: static;
text-indent: 0;
border: 1px solid #3a87ad;
background-color: #3a87ad;
color: whitesmoke;
}
.event:nth-child(5):hover::before{
display:none;
}
.event:nth-child(5):hover ~ .event:nth-child(n){
display: block;
}
And for .event-box class I have commented out max-height: 76px; because in my browser 76px was not equal to the height of four .event elements stacked. Also removed update function.
I dont think it's possible using css only. but for better approach in what you are trying to do.instead of using max-height for .event-box I use this css which is add display:none to +4.event on your event container:
.event-box .event-container .event:nth-child(n+5){
display: none;
}
and now when it's more than 4 .event your more text appears. FIDDLE
UPDATE:
HERE I make little change in you js as well and make it more professional,
while you are using template to render the page, maybe you can do it as follow
<div class="event-container">
{{#each events}}
<div class="event">{{event-name}}</div>
{{/each}}
</div>
{{#if canshowmore}}
<div class="more-events">more ...</div>
{{/if}}
and
function canshowmore() {
return events.length >= 4;
}

How to build sliding horizontal menu. CSS

I'm trying to build a simple slider that consists of a static 'window' and movable list of items.
where parent container shows only one item and hides all the rest.
I've tried to do something like this but appears this is wrong:
<div id="category-selector">
<div class="categories-list clearfix">
<a class="category">sports</a>
<a class="category">fashion</a>
<a class="category">health</a>
</div>
</div>
#category-selector {
width: 300px; margin: 0 auto; position: relative; z-index: 1;
border: 2px solid #ccc;
-moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; height: 55px;
overflow: hidden;
}
.categories-list {
position: absolute; top: 0; left: 0; display: block;
}
a.category {
display: block; float: left; width: 100%; padding: 10px;
font-size: 30px; font-family: Cambria, 'Segoe UI', sans-serif; line-height: 35px;
text-decoration: none; text-align: center; color: #42a6ce;
}
How do I achieve this functionality?
Try this:
.categories-list {
display: block;
white-space: nowrap;
/*margin-left: -300px;*/
}
a.category {
display: inline-block;
width: 280px;
padding: 10px;
font-size: 30px; font-family: Cambria, 'Segoe UI', sans-serif; line-height: 35px;
text-decoration: none; text-align: center; color: #42a6ce;
}
If you want to have links arranged from left to right, you should set them fixed width. If you set 100% then they will always try to fill container. Setring display to inline-block allows us to avoid wraping line by setting white-space: nowrap; on container.
To scroll it just set margin on container for example margin-left: -300px;
Working sample: http://jsfiddle.net/N9R2E/
Alternatively you may try this:
.categories-list {
display: block;
white-space: nowrap;
margin-left: -300px;
width: 10000px; /* long enough to fit all links */
}
a.category {
display: block;
float:left;
width: 280px;
padding: 10px;
font-size: 30px; font-family: Cambria, 'Segoe UI', sans-serif; line-height: 35px;
text-decoration: none; text-align: center; color: #42a6ce;
}
This uses display:block and float:left like in your attempt, but widths are fixed. To have all links in one line categories-list must be wider then all links together.
Working sample: http://jsfiddle.net/N9R2E/3/
If you don't mind using JS or buttons, this is one way to do it.
$(document).ready(function() {
var slider = $("#categoriese_list");
var leftProperty, newleftProperty;
// the click event handler for the right button
$("#right_button").click(function() {
// get value of current left property
leftProperty = parseInt(slider.css("left"));
// determine new value of left property
if (leftProperty - 100 <= -900) {
newLeftProperty = 0; }
else {
newLeftProperty = leftProperty - 100; }
// use the animate function to change the left property
slider.animate( {left: newLeftProperty}, 1000);
}); // end click
// the click event handler for the left button
$("#left_button").click(function() {
// get value of current right property
leftProperty = parseInt(slider.css("left"));
// determine new value of left property
if (leftProperty < 0) {
newLeftProperty = leftProperty + 100;
}
else {
newLeftProperty = -800;
}
// use the animate function to change the left property
slider.animate( {left: newLeftProperty}, 1000);
}); // end click
}); // end ready
However, I would recommend making your categories list out of a <ul> to keep it more in line.
What you're talking about is essentially a carousel or slider. Rather than trying to code it from scratch I would just use one of the million jQuery plugins out there to build this. I personally like bxslider a lot for things like this because it's responsive and very simple to implement.

Categories

Resources