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;
}
}
}
Related
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>
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>
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>
I've spent some time working on a slider that has a div follow the thumb of slider. I did this by creating a relatively positioned container for the follower (called #slider-follower-cntnr). I then adjust the position of the follower div (#slider-follower) according to the value of the range input. The problem is that as you move the thumb across the track the follower does not stay perfectly centered against the position of the thumb. I've tried adjusting the width of the #slider-follower-cntnr but I don't no how to find the correct width to keep it perfectly centered. Thanks for any help.
TL/DR: How can I keep follower div centered perfectly to the thumb of the range input across all range values?
Heres a codepen. You may need to full screen to see it get off center as you pull it along the range.
HTML
<div id="slider-cntnr">
<input type="range" id="frame-slider" oninput="updateFollowerValue(this.value)" />
<div id="slider-follow-cntnr">
<div id="slider-follow">
<div id="slider-val-cntnr">
<span id="slider-val"></span>
</div>
</div>
</div>
</div>
JS
var follower = document.getElementById('slider-follow');
var follower_val = document.getElementById('slider-val');
var slider = document.getElementById('frame-slider');
var updateFollowerValue = function(val) {
follower_val.innerHTML = val;
follower.style.left = (val*1) + '%';
};
updateFollowerValue(slider.value);
CSS
html, body {
width: 100%;
height: 100%;
}
#slider-cntnr {
width: 80%;
margin: 40px;
position: relative;
display: flex;
flex-direction: column;
background: orange;
}
#frame-slider {
width: 100%;
margin: 0;
}
#slider-follow-cntnr {
position: relative;
background-color: blue;
height: 10px;
margin: 0 auto;
width: 98%;
}
#slider-follow {
background-color: black;
width: 30px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
margin-left: -15px;
}
#slider-val-cntnr {
background-color: white;
width: 25px;
height: 20px;
}
#slider-val {
margin-left: 9px;
}
Few ways you can fix this:
(1) In the HTML
<div id="slider-val-cntnr">
<center>
<span id="slider-val"></span>
</center>
</div>
(2) In the CSS
#slider-val {
margin-left: auto;
margin-right: auto;
}
(1) The HTML method probably works the best, but it's generally not best practice to have <center> tags throughout your HTML.
(2) This will make sure that the number never goes beyond the bounds of the white box that it resides in. If you don't care that it is absolutely centered, and just want the number to not exit the box, then this is a suitable solution.
I am trying to center these images vertically inside of the table without having to edit the picture so that they are the same size. Tried a few things... I know whenever I want to center something horizontally I use margin-left: auto; margin-right: auto; So I thought maybe the same would apply here, but with top and bottom, but no dice.
EDIT: Here is another idea... would it be possible to set up a javascript to run as the page is opened to position all of the text spans as low as the lowest span in that row?
Just a thought... let me know what you think
Any help would be much appreciated.
Here is the fiddle: http://jsfiddle.net/58u4g/1/
Thanks in advance
CSS vertical alignment is different across all browsers - especially if you want to keep the text in the same cell.
I recommend creating a fixed height block for the images to go in, and using a vertical align hack to get the image vertically centered within that div (I know, hacks are bad).
JSFiddle: http://jsfiddle.net/58u4g/8/
Vertical align hack: http://www.jakpsatweb.cz/css/css-vertical-center-solution.html
Relevant CSS:
.valign {
width: 100%;
display: block;
display: table;
height: 100%;
#position: relative;
overflow: hidden;
}
.valign > span {
display: block;
#position: absolute;
#top: 50%;
display: table-cell;
vertical-align: middle;
}
.valign> span > span {
display: block;
#position: relative;
#top: -50%;
}
#posiflex_directory td .image {
height: 160px;
display: block;
}
I'd do it differently for the sake of separating elements to have better control over them, even though my fiddle is not clean and is a mash of your sample plus the bits I through in :)
<table id="posiflex_directory">
<tr class="theimgs">
<td>
<a href="../posiflex/tx_overview.aspx" id="posiTXIcon">
<span class="valigner"></span>
<img height="125" src="https://www.metsales.com/MetropolitanSales/microsite/posiflex/images/home_icons/tx-4200.png" width="200"/>
</a>
</td>
<td>
<a href="../posiflex/cd_overview.aspx" id="posiCDIcon">
<span class="valigner"></span>
<img height="103" src="https://www.metsales.com/MetropolitanSales/microsite/posiflex/images/home_icons/CR6300.png" width="200"/>
</a>
</td>
</tr>
<tr>
<td class="imgtext"><span>TX Fan-Free Series</span></td>
<td class="imgtext"><span>Cash Drawers</span></td>
</tr>
</table>
#posiflex_directory {
text-align: center;
}
#posiflex_directory a {
color: inherit;
position: relative;
}
#posiflex_directory td {
border: solid 1px;
}
#posiflex_directory .theimgs {
width: 215px;
height: 225px;
padding: 5px;
border: solid 1px;
}
#posiflex_directory span {
left: 0;
right: 0;
top:100%;
bottom: 5px;
text-decoration: underline;
font-weight: bold;
}
img {
border: solid 1px;
}
.valigner {
display: inline-block;
height: 100%;
vertical-align: middle;
}
.imgtext{
height:40px;
}