I have a grid set up where the blocks are centre aligned, thus I've done this using display: inline block and set text-align: center to the container. BUT now the client wants variable heights on the blocks which now leaves big gaps in the grid as they're inline-block. Alternatively I could use float: left but this won't work as the blocks need to be centred. I have a codepen setup here: https://codepen.io/anon/pen/WOaeve
I usually use the isotope plugin for grids but there's no layout mode that'll allow for centre aligned blocks so I need a solution that'll allow for all the gaps in the grid to be filled AND for the blocks to be centred. Here's my CSS markup also:
.feed-grid {
position: relative;
display: block;
width: 100%;
height: auto;
text-align: center;
font-size: 0;
}
.feed-grid .grid-block {
display: inline-block;
vertical-align: top;
margin-left: 6px;
margin-right: 6px;
margin-bottom: 12px;
width: auto;
height: 255px;
}
.feed-grid .grid-block.large {
height: 522px;
}
.feed-grid .grid-block img {
position: relative;
display: block;
width: auto;
height: 255px;
}
.feed-grid .grid-block.large img {
height: 522px;
}
Any solutions to this would be greatly appreciated!
It may solve your problem. I have used float: left; in .child elements.
.container {background: green; overflow: hidden; text-align: center; padding: 15px;}
.center-element {float: none; background: yellow; overflow: hidden; width: auto; box-sizing: border-box; display: inline-block; padding: 5px; vertical-align: middle;}
.child {float: left; padding: 12px 24px; background-color: red;}
.child:not(:first-child) {margin-left: 5px;}
<div class="container">
<div class="center-element">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
What about a vertical middle alignement in the cases you have a smaller image than its "row" ?
Here is a CodePen
$(document).ready(function(){
var rowHeight = 0;
var rowHeights = [];
var rowCount = 0;
var offset = $(".grid-block").first().offset().top;
// Loop throught all images to get their heights.
$(".grid-block img").each(function(){
// If on the same row
if($(this).offset().top == offset){
// Find the biggest height
if($(this).height() > rowHeight){
rowHeight = $(this).height();
rowHeights[rowCount] = rowHeight;
}
// If the row is different.
}else{
// Get the new row offset.
offset = $(this).offset().top;
rowCount++;
rowHeight = $(this).height();
rowHeights.push(rowHeight);
}
// Set a custom attribute to apply the right margins.
$(this).attr("data-row",rowCount);
});
//Here you have the array of row heights in console.
console.log(JSON.stringify(rowHeights));
// Loop again to apply some margins.
$(".grid-block img").each(function(){
var thisRowHeight = rowHeights[parseInt($(this).data("row"))];
// Apply the margin if this image is smaller than the row height.
if( $(this).height() < thisRowHeight ){
var margin = (thisRowHeight - $(this).height() )/2;
$(this).css({"margin":margin+"px 0"});
}
});
});
It "measures" the row height to apply a margin to small images... Making them at the middle.
Related
The project:
I made a 3 items slider just using CSS and JS. I'm trying to adjust the proportion of one item to make sliding based on this proportion.
The problem:
the proportion isn't fixed and there is a slight space from the left side of all items and between items themselves. It seems they have borders that take a tiny space. and that space also affects sliding itself. I don't know if it's a CSS or JS problem!
Source Code on Codepen
HTML
<div id="slider">
<div class="SlideContainer">
<div class="img">
<img src="https://www.nicepng.com/png/detail/11-112605_punk-cat-berkley-cats-illustrations.png">
</div>
<h1 style="text-align:center;">1</h1>
</div>
<div class="SlideContainer">
<div class="img">
<img src="https://i.pinimg.com/736x/84/78/b9/8478b93283dc6eac074d437097a9fe74.jpg">
</div>
<h1 style="text-align:center;">2</h1>
</div>
...... etc
</div>
CSS
#slider {
height: 500px;
margin: 0;
padding: 0 .5%;
overflow: hidden;
white-space: nowrap;
scroll-behavior: smooth;
}
.SlideContainer{
vertical-align: top;
background-color: purple;
color: white;
height: 99% ;
margin: .5% 0;
width: 33%;
display: inline-block;
}
.img {
overflow: hidden;
max-width:200px;
max-height:200px;
border-radius: 50%;
display: block;
margin: 10px auto 0 auto;
text-align: center;
}
.img img{
height: 200px;
width: 200px;
}
JS
var Container = document.getElementById("slider");
var unitWidth = (Container.offsetWidth/3);
var slidesNo = (document.getElementsByClassName("SlideContainer").length - 2);
var i = 0;
var positionInfo = Container.getBoundingClientRect();
var height = positionInfo.height;
var width = (positionInfo.width/3);
function SlideLoop(){
var interval = setInterval(function(){
Container.scrollTo((unitWidth * i), 0);
//Container.scrollBy(unitWidth, 0);
i++;
if(i == slidesNo) {
i = 0;
clearInterval(interval);SlideLoop();
}
}, 1500);
};
SlideLoop();
Your problem is with using white-space: nowrap; in the slider and display: inline-block; in the slider items.
Using such methods to display items is not recommended because it would cause strange unexpected behavior. I suggest you learn flexbox. This is a great and easy guide that will help you.
as for your problem, change those css elements like this and it should work propely:
#slider {
height: 500px;
margin: 0;
padding: 0 .5%;
overflow: hidden;
scroll-behavior: smooth;
display: flex; /* displays items horizontally */
}
.SlideContainer{
vertical-align: top;
background-color: purple;
color: white;
height: 99% ;
margin: .5% 0;
min-width:33%; /* force the minimum width of items */
}
I am trying to smooth out this custom animation.
See Working Animation Here.
The problem I am having is that when the city name revolves up and replaces the old one, the text-align center causes the h2 text to re-align center in one frame. I want to smooth out this transition so it eases into the align center instead of just jumping to it.
I hope that explanation helps. Here is my code.
HTML
<div class="coverage">
<h2>Kellin has service in <span class="flip"></span></h2>
<ul class="coverage_list">
<li>Larkspur</li>
<li>Castle Rock</li>
<li>Monument</li>
<li>Palmer Lake</li>
<li>Colorado Springs</li>
<li>Pueblo</li>
<li>Peyton</li>
<li>Falcon</li>
<li>Calhan</li>
<li>Franktown</li>
<li>Elizabeth</li>
<li>Elbert</li>
<li>Glenwood Springs</li>
<li>Rifle</li>
<li>Silt</li>
<li>El Jebel</li>
<li>Carbondale</li>
<li>New Castle</li>
<li>Parachute</li>
<li>Battlement</li>
</ul>
</div><!-- end .coverage -->
CSS
/* Coverage Banner */
.coverage{
border: 2px solid #333;
width: 100%;
}
.coverage ul.coverage_list{
display: none;
}
.coverage h2{
font-size: 2em;
font-weight: 700;
padding: 0px;
margin:0px;
overflow: hidden;
display: block;
text-align: center;
white-space: nowrap;
}
.coverage h2 .flip{
display: inline-block;
position: relative;
padding: 0px;
margin: 0px;
}
.coverage h2 .flip .current{
position: relative;
left:0;
display: inline-block;
text-align: left;
width: 100%;
padding: 0px;
margin: 0px;
}
.coverage h2 .flip .newcity{
position: absolute;
display: inline-block;
text-align: left;
white-space: nowrap;
left: 0;
padding: 0px;
margin: 0px;
}
JS / Jquery
var coverageVars = {
index : 1,
count : 0,
flipTime : 500
}
// .current = Current City, position relative
// .newcity = New City, position absolute;
$(document).ready(function(){
// Load First City Into H2 Display
var firstCity = $('ul.coverage_list li:nth-child(1)').html();
$('.coverage h2 .flip').append('<span class="current">'+firstCity+'!</span>');
// Get Count
coverageVars.count = $('ul.coverage_list').children('li').length;
var flipTimer = setInterval(function(){
// Increase Counter
if( coverageVars.index < coverageVars.count ){
coverageVars.index += 1;
} else {
coverageVars.index = 1;
}
// Get City Names
var currentCity = $('.coverage h2 .flip .current').html();
var newCity = $('ul.coverage_list li:nth-child('+coverageVars.index+')').html();
// Append newcity span to flip element
$('.coverage h2 .flip').append('<span class="newcity" style="top:50px;">'+newCity+'!</span>');
$('.coverage h2 .flip .current').animate({top:'-50px'}, coverageVars.flipTime, function(){
$(this).remove();
});
$('.coverage h2 .flip .newcity').animate({top:0}, coverageVars.flipTime, function(){
console.log('done!');
$(this).removeClass('newcity').addClass('current');
});
}, 1500);
});
I figure i would have to align with margins and then put a css transition on the margins but I can't figure it out. Thanks for the help.
An other idea:
Get the width of your <h2> (without .flip)
Get the width of the next <li> that will be appended. For this .coverage_list can't be set to display: none, but you can set the height: 0 and overflow to hidden.
Animate your <h2> to the new width (<h2> + <li>). Maybe with 1-2px more, due to browser rendering
Repeat steps #2 and #3 and always animate the width before appending
I have 4 li's with a div having a background image (through CSS). I'm using flexbox for the layout. I want it to have columns with 3 li's in each column. Everything is working fine besides for the div containing image. The height of the div is larger than its parent.
The weird thing is, when I make it into rows instead of columns, it has the correct height.
(If it shows the correct size by you, then try making the windows width wider.)
How can I make the div to have the correct size?
JSFiddle
$(document).ready(function () {
"use strict";
function resizeHeightLi() {
$('li').css('height', 'calc(' + $('li').width() + 'px / 1.8)');
}
resizeHeightLi();
$(window).resize(function () {
resizeHeightLi();
});
});
html, body {
margin: 0;
height: 100%;
}
div {
align-items: center;
justify-content: center;
height: 100%;
display: flex;
overflow: auto;
background-color:aqua;
}
ul {
margin-top: auto;
margin-bottom: auto;
flex-basis: 70%;
height: 80%;
padding: 0;
display: inline-flex;
flex-wrap: wrap;
/*flex-direction: row; // When it's set to row, it works fine.*/
flex-direction: column;
}
li {
flex-basis: calc(100% / 3 - 2px); /* Subtract the border */
color: firebrick;
list-style-type: none;
border: 1px solid firebrick;
}
.image {
background-image: url("http://i.imgur.com/nswXRR4.jpg");
background-size: contain;
background-repeat: no-repeat;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul>
<li><div class="image"><span>1</span></li>
<li><div class="image"><span>2</span></li>
<li><div class="image"><span>3</span></li>
<li><div class="image"><span>4</span></li>
</ul>
</div>
Since the height of each li is taken care of by your flex-basis rule in the CSS, I think there is no need to assign the height again with JavaScript. Instead, you can get the height of each li after the flex calculations are done and assign it to your image divs. That way, both parent and child elements are the same height.
function resizeHeightLi() {
$('.image').css('height', $('li').height() + 'px');
}
EDIT (CSS Only)
To accomplish the same purely with CSS, you can delete all the JS you have now and add the following to your CSS:
// In addition to what you already have in your li
li {
// ...
position: relative;
}
// Same here, in addition to what you have in .image
.image {
// ...
position: absolute;
width: 100%;
height: 100%;
}
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)
I have a container with a bunch of equally sized elements. The container has a width of 100% up to a certain px amount, so if a user shrinks their screen down, elements from the first row may be moved down to the second row to fit, and from the second row to the third row, etc.
I'd like the .spacer div to act as a pseudo margin so that the first element in the second row of divs, no matter what div it actually is, will be spaced 250px out from the left side of the container. I want that .spacer div to always remain at a fixed point relative to the container (right at the beginning of the second row) but also affect the position of the first div in that row. How can I accomplish this with CSS? Open to JS solutions as well.
Here's a Codepen that shows the situation I'm describing:
https://codepen.io/anon/pen/QMMyLj
Any ideas?
Not sure, but check if you are looking something like this:
.container {
background-color: black;
width: 80%;
max-width: 1800px;
min-height: 1000px;
padding: 10px 5px;
text-align: center;
margin: 0 auto;
}
.square {
display: inline-block;
height: 250px;
width: 250px;
background-color: white;
float: none;
margin-left: 5px;
margin-right: 5px;
margin-bottom: 20px;
text-align: center;
line-height: 250px
}
<div class="container">
<div class="square">1</div>
<div class="square">2</div>
<div class="square">3</div>
<div class="square">4</div>
<div class="square">5</div>
<div class="square">6</div>
<div class="square">7</div>
<div class="square">8</div>
<div class="square">9</div>
<div class="square">10</div>
<div class="square">11</div>
<div class="square">12</div>
<div class="square">13</div>
<div class="square">14</div>
<div class="square">15</div>
</div>
Here is a possible solution using css grid and variables. It uses css-grid to layout the red spacer, and javascript to update the number of columns required. (Note that they are only supported in modern browsers http://caniuse.com/css-grid/embed)
CSS
:root {
--colNum: 1;
}
.container {
display: grid;
justify-content: left;
grid-template-columns: repeat(var(--colNum), auto);
}
.square {
height: 250px;
width: 250px;
background-color: white;
}
.spacer {
background-color: red;
width: 250px;
grid-row: 2 / span 1;
grid-col: 1 / span 1;
}
JS
function setNoOfColumns(){
columns = Math.floor(window.innerWidth / 250);
document.documentElement.style.setProperty("--colNum", columns);
}
window.addEventListener("resize", function(){
setNoOfColumns();
});
setNoOfColumns();
Code: https://codepen.io/anon/pen/mMMPwO