Looking at the different masonry approaches out there, and specifically looking at the summary here
https://css-tricks.com/piecing-together-approaches-for-a-css-masonry-layout/
It is said: "Is vertical order with ragged bottoms OK?"
With a code pen theoretically showing this ragged bottoms, here
https://codepen.io/chriscoyier/pen/NeRNBO or here https://codepen.io/chriscoyier/pen/XojXxy
But I cannot see where are the ragged bottoms
Either I need some clue, or this is an issue the browsers have already solved?
(the approach in the codepen, pure css)
.masonry-with-columns {
columns: 6 200px;
column-gap: 1rem;
div {
width: 150px;
background: #EC985A;
color: white;
margin: 0 1rem 1rem 0;
display: inline-block;
width: 100%;
text-align: center;
font-family: system-ui;
font-weight: 900;
font-size: 2rem;
}
#for $i from 1 through 36 {
div:nth-child(#{$i}) {
$h: (random(400) + 100) + px;
height: $h;
line-height: $h;
}
}
}
(Or the flex-based one)
.masonry-with-flex {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 1000px;
div {
width: 150px;
background: #EC985A;
color: white;
margin: 0 1rem 1rem 0;
text-align: center;
font-family: system-ui;
font-weight: 900;
font-size: 2rem;
}
#for $i from 1 through 36 {
div:nth-child(#{$i}) {
$h: (random(400) + 100) + px;
height: $h;
line-height: $h;
}
}
}
What the screenshot in your question demonstrates is the perfect example of ragged bottoms. In fact the linked article states you need to be OK with "Vertical Ordering and Ragged Bottoms".
Flush masonry is not currently achievable with CSS alone. A subsequent section titled Do you need a clean bottom edge? A Flexbox/JavaScript combo can help. demonstrates an effective hybrid approach.
Related
I can't figure out why I'm getting this little bit of green when the window is an odd number of pixels wide. I think it has something to do with sub-pixel rendering, but I'm just not sure where the green is coming from. It's just the 2nd div too which is weird.
I have some script that is animating the BG of this div. I'm sure this is part of the issue, but I can't figure out why it's only happening to my 2nd div.
I tried to manually set the width of this div, but I was hoping it would be responsive and scale with the window size.
let currentStage = 1
function performAction(selectedStage) {
currentStage = selectedStage
let stages = document.body.getElementsByClassName('stage-flow-item')
let stageLines = document.body.getElementsByClassName('stage-flow-line')
console.log("selectedStage: " + selectedStage)
for (let stage of stages) {
if (stage.id > currentStage) {
stage.classList.remove('completed')
stage.classList.add('active')
} else {
stage.classList.remove('active')
stage.classList.add('completed')
}
}
for (let stageLine of stageLines) {
if (stageLine.id > currentStage) {
stageLine.classList.remove('lineCompleted')
stageLine.classList.add('lineActive')
} else {
stageLine.classList.remove('lineActive')
stageLine.classList.add('lineCompleted')
}
}
}
.stage-flow-container {
display: flex;
justify-content: space-between;
align-items: center;
height: 70px;
padding: 0 30px;
}
.stage-flow-item {
width: 70px;
height: 70px;
min-width: 70px;
border-radius: 50%;
background-color: #ddd;
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
color: #fff;
cursor: pointer;
}
.stage-flow-item.active {
background-color: #ddd;
}
.stage-flow-item.completed {
background-color: #6ab04c;
}
.stage-flow-line {
width: calc(100vw);
height: 6px;
background-color: #ddd;
/* default color */
background: linear-gradient(to left, #ddd 50%, #6ab04c 50%) right;
position: relative;
background-size: 200%;
transition: .5s ease-out;
}
.stage-flow-line.lineCompleted {
background-position: left;
background-color: #6ab04c;
}
.stage-flow-line.lineActive {
background-position: right;
background-color: #ddd;
}
<div class="stage-flow-container">
<div id=1 class="stage-flow-item" onclick="performAction(1)">1</div>
<div id=1 class="stage-flow-line"></div>
<div id=2 class="stage-flow-item" onclick="performAction(2)">2</div>
<div id=2 class="stage-flow-line"></div>
<div id=3 class="stage-flow-item" onclick="performAction(3)">3</div>
</div>
I'm not sure if this is on the right track, but I'd eliminate the odd 100vw width on the connectors and instead make them flex. I'd then remove the 200% background size multiplier. By setting the gradient points to 100% the problem is gone. I really don't know if this covers your use case, though.
I converted from background gradient to a pseudo-element solution for the color transition. I think it's simpler. You'd probably have to use CSS animations (as opposed to simple transitions) to make it work otherwise. Of course, you could apply the same principle to the stage items as well, implementing a delay to crate a consistent animation across the item and the line.
Note that duplicated ID values are invalid in HTML. They must be unique. I've refactored to use data attributes instead and an event listener instead of inline JavaScript.
const stageEls = document.querySelectorAll('.stage-flow-item')
const lineEls = document.querySelectorAll('.stage-flow-line')
let currentStage = 1
stageEls.forEach(el => {
el.addEventListener('click', () => {
performAction(el.dataset.stage)
})
})
function performAction(selectedStage) {
currentStage = selectedStage
for (let el of stageEls) {
if (el.dataset.stage > currentStage) {
el.classList.remove('completed')
el.classList.add('active')
} else {
el.classList.remove('active')
el.classList.add('completed')
}
}
for (let el of lineEls) {
if (el.dataset.stage > currentStage) {
el.classList.remove('lineCompleted')
el.classList.add('lineActive')
} else {
el.classList.remove('lineActive')
el.classList.add('lineCompleted')
}
}
}
.stage-flow-container {
display: flex;
align-items: center;
height: 70px;
padding: 0 30px;
}
.stage-flow-item {
width: 70px;
height: 70px;
min-width: 70px;
border-radius: 50%;
background-color: #ddd;
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
color: #fff;
cursor: pointer;
}
.stage-flow-item.active {
background-color: #ddd;
}
.stage-flow-item.completed {
background-color: #6ab04c;
}
.stage-flow-line {
flex: 1;
height: 6px;
background: #ddd;
position: relative;
}
.stage-flow-line::after {
position: absolute;
content: '';
top: 0;
left: 0;
width: 0;
height: 100%;
background: #6ab04c;
transition: all 0.5s ease-out;
}
.stage-flow-line.lineCompleted::after {
width: 100%;
}
<div class="stage-flow-container">
<div data-stage=1 class="stage-flow-item">1</div>
<div data-stage=1 class="stage-flow-line"></div>
<div data-stage=2 class="stage-flow-item">2</div>
<div data-stage=2 class="stage-flow-line"></div>
<div data-stage=3 class="stage-flow-item">3</div>
</div>
EDIT: Changed the post name, which was incorrectly titled from another post !!
I have been building a sports app in React over the last several months, and I am struggling with a small cosmetic issue with my radio buttons. Immensely frustrating is the fact that despite my attempt at a reproducible example, the bug does not appear in my example below, although fortunately a variant of the issue is occurring. Here are my buttons:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
oneTwoFour: "1 Graph",
quarter: "All"
}
}
handleQuarterChange = (event) => {
this.setState({ quarter: event.target.value });
};
handleOneTwoFourChange = (event) => {
this.setState({ oneTwoFour: event.target.value });
};
render() {
const { oneTwoFour, quarter } = this.state;
const oneTwoFourOptions = ["1 Graph", "2 Graphs", "4 Graphs"];
const oneTwoFourButtons =
<form>
<div className="blg-buttons">
{oneTwoFourOptions.map((d, i) => {
return (
<label key={'onetwofour-' + i}>
<input
type={"radio"}
value={oneTwoFourOptions[i]}
checked={oneTwoFour === oneTwoFourOptions[i]}
onChange={this.handleOneTwoFourChange}
/>
<span>{oneTwoFourOptions[i]}</span>
</label>
)
})}
</div>
</form>;
const quarterOptions = ["All", "OT", "Half 1", "Half 2", "Q1", "Q2", "Q3", "Q4"];
const quarterButtons =
<form>
<div className="blg-buttons">
{quarterOptions.map((d, i) => {
return (
<label key={'quarter-' + i} style={{"width":"50%"}}>
<input
type={"radio"}
value={quarterOptions[i]}
checked={quarter === quarterOptions[i]}
onChange={this.handleQuarterChange}
/>
<span>{quarterOptions[i]}</span>
</label>
)
})}
</div>
</form>;
return(
<div>
<div style={{"width":"25%", "float":"left", "margin":"0 auto", "padding":"5px"}}>
{quarterButtons}
</div>
<div style={{"width":"25%", "float":"left", "margin":"0 auto", "padding":"5px"}}>
{oneTwoFourButtons}
</div>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
.blg-buttons {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.blg-buttons input[type=radio] {
visibility:hidden;
width:0px;
height:0px;
overflow:hidden;
}
.blg-buttons input[type=radio] + span {
cursor: pointer;
display: inline-block;
vertical-align: top;
line-height: 1;
font-size: 1.0vw;
padding: 0.5vw;
border-radius: 0.35vw;
border: 0.15vw solid #333;
width: 90%;
text-align: center;
color: #333;
background: #EEE;
}
.blg-buttons input[type=radio]:not(:checked) + span {
cursor: pointer;
background-color: #EEE;
color: #333;
}
.blg-buttons input[type=radio]:not(:checked) + span:hover{
cursor: pointer;
background: #888;
}
.blg-buttons input[type=radio]:checked + span{
cursor: pointer;
background-color: #333;
color: #EEE;
}
.blg-buttons label {
line-height: 0;
font-size: calc(0.85vw);
margin-bottom: 0.1vw;
width: 90%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"></script>
<div id='root'>
Come On Work!
</div>
Also, here is a screenshot of an inspection of the buttons in my app (can be found at bigleaguegraphs.com/nba/shotcharts-pro as well), showing the true error that I am having:
The error is in this overhang of the buttons that is not due to padding or margin. I have seemingly gone through every single aspect of the CSS styling my radio buttons, and I have no idea why the element extends a few extra pixels outward to the right.
Amazingly / unfortunately, this is not occurring in the example above, although there is a different issue in the example above where the label element extends a few extra pixels upward (instead of rightward), that I cannot account for.
Any help with removing this extra couple of pixels on the button group would be very much appreciated!
.blg-buttons {
display: flex;
justify-content: center;
/* flex-wrap: wrap; you shouldn't need this */
flex-direction: column;
flex: 1;
}
.blg-buttons label {
display: flex;
line-height: 0;
font-size: 0.85vw;
flex: 1;
align-items: center;
margin-bottom: 5px; /* you don't need that 0.1vw */
font-weight: 700;
}
.blg-buttons input[type=radio]+span {
cursor: pointer;
display: flex;
flex: 1;
justify-content: center;
vertical-align: top;
line-height: 1;
font-size: 1vw;
padding: .5vw;
border-radius: .35vw;
border: .15vw solid #333;
width: 90%;
/* text-align: center; <-- you don't need this with flex */
color: #333;
background: #eee;
}
You should try and use flexbox where possible. I worked this out by playing with your site, so where i saw .nba_scp_cp_rbs i replaced with .blg-buttons (hope that's right). But yeh, avoid using stuff like width: 90%, with flex you rarely have to explicitly define widths, and you can size things based on padding & margins, leading to way less weird sizing bugs like yours :)
picture proof of it working
I can't seem to get the effect working. I know it can be done with css transitions/keyframes, but I'd prefer it in Velocity. Other effects work, and I'm using the same syntax, so I'm at a loss for what's causing this. I tried iterating through the document.getElementsByClass('menu') inside the function too, though Velocity does that by itself as far as I know. I also tried testing with just a single element id instead of a class. Nothing worked.
When I used the HTML onmouseover tag, however, I kept getting reference errors - function not defined.
var varb = document.getElementsByClassName('menu');
for (var i = 0; i < varb.length; i++) {
varb[i].addEventListener("mouseover", menuHover);
}
function menuHover() {
Velocity(varb, {
border: "1px",
border: "blue"
}, {
duration: 500
});
}
#navContainer {
display: flex;
justify-content: center;
width: 60%;
justify-content: space-around;
align-items: center;
}
.menu {
display: flex;
font-size: 0.77rem;
font-weight: bold;
width: 16%;
margin: 0 0.2rem 0 0.2rem;
height: 2rem;
justify-content: center;
line-height: 2rem;
font-family: Arial Black, sans-serif;
}
<nav id="navContainer">
<div class="menu">HOME</div>
<div class="menu">GALLERY</div>
<div class="menu">ACTIVITIES</div>
<div class="menu">ABOUT US</div>
<div class="menu">PRICE</div>
<div class="menu">CONTACT</div>
</nav>
my question today probably has an easy answer, however I have found a few working examples but can't seem to transfer it to my web page.
I am trying to use an image for a link, and would like the image to change when you hover over it. The link below is what I am trying to accomplish, but for whatever reason when I substitute my code from my page to it, it doesn't work.
EXAMPLE http://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_ev_onmouseover
I am completely lost now and just need a little help. Here is my code.
DEMO
function hoverImg(x) {
x.style.backgroundImage = "url(image/arrowBtnHover.png)"
x.style.transition = "ease 0.5s"
}
function normalImg(x) {
x.style.backgroundImage = "url(image/arrowBtn.png)"
}
#header {
background-color: #473D39;
height: 100%;
width: 100%;
display: table;
position: absolute;
z-index: 10;
}
#wrapper {
display: table-cell;
vertical-align: middle;
}
#header h1 {
text-align: center;
margin: 0px;
font-size: 80px;
padding-top: 5%;
font-weight: normal;
color: #FFF;
letter-spacing: 18px;
text-transform: uppercase;
}
#header h5 {
text-align: center;
color: #FFF;
margin: 15px 15px 50px;
font-weight: normal;
text-transform: uppercase;
font-size: 14px;
letter-spacing: 2px;
}
<div id="header">
<div id="wrapper">
<h1>Premier Webster</h1>
<h5>Local Web Design For The Profesional In You</h5>
<img onmouseover="hoverImg(this)" onmouseout="normalImg(this)" src="image/arrowBtn.png" />
</div>
</div>
Please take a look at https://jsfiddle.net/avzfdc2j/3/
It has been done using css with background image and transition
div.smile {
background-image: url("http://images.clipartpanda.com/stupidity-clipart-1320682287266972230curius_face.svg.hi.png");
background-size: 60px 60px;
height: 60px;
width: 60px;
cursor: pointer;
}
div.smile:hover {
background-image: url("http://images.clipartpanda.com/straight-face-clipart-black-and-white-smiley-face-hi.png");
transition: ease 0.5s;
}
<div class="smile"></div>
You should be changing the src attribute instead:
function hoverImg(x) {
x.src = "image/arrowBtnHover.png"
x.style.transition = "ease 0.5s"
}
function normalImg(x) {
x.src = "image/arrowBtn.png"
}
But I don't think that the transition will work with this.
Since it's an image, you need to change it's src property, not it's CSS.
function hoverImg(x) {
x.src = "image/arrowBtnHover.png"
x.style.transition = "ease 0.5s"
}
function normalImg(x) {
x.src = "image/arrowBtn.png"
}
I have a strange issue with a script that I've created. My jQuery/Javascript skills aren't great (I'm still learning) and am hoping someone could help me understand why this is happening.
I'm developing an online store and have a strip of 4 divs floated next to each other across the top with notices I'd like to highlight for my customers.
The site is responsive, so for mobile I wanted to reduce this to one notice at a time, and fade out and fade in each notice.
I also didn't want to simply use CSS media queries to show and hide a desktop and mobile version as I feel that might work against me, SEO-wise, if I was to repeat the content twice. Therefore I've put together a jQuery script to grab the content of the first set of divs, put them into an array, and fade in and out each notice in a loop.
I thought I'd done it however noticed something strange in both Firefox and Chrome: it loops through once fine, but then stops completely when displaying "100% happiness guarantee" the second time, and I'm at a loss as to why.
I've created a JSFiddle with the code I'm using here:
http://jsfiddle.net/qewwmnge/
$(document).ready(function() {
// Transform the highlights div into a 1 line bar for mobile devices
// Read the highlights div content into an array
var highlights = new Array();
$("#highlights").find("div").each(function(){
highlights.push($(this).html());
});
$text = $('#highlights-mobile div'),
delay = 5;
// Set the initial highlight item on page load
$text.html( highlights[0] );
// Loop through the array and fade in each highlight
function loop ( delay ) {
$.each( highlights, function ( i, elm ){
if ($text.html() != highlights[i]) { // Skip the first fade in on the first loop so it doesn't repeat itself
$text.delay( delay*1E3).fadeOut();
$text.queue(function(){
$text.html( highlights[i] );
$text.dequeue();
});
$text.fadeIn();
$text.queue(function(){
if ( i == highlights.length -1 ) {
loop(delay);
}
$text.dequeue();
});
}
});
}
loop( delay );
});
If anyone could tell me what I'm doing wrong I'd really appreciate it!
Your jQuery code contain queue/dequeue logic, there is no need to do that.
It's better to use simple jquery for same thing. See this demo JSFiddle
$(function () {
var $highlights = $("#highlights-mobile div");
var divsHTML = new Array();
$("#highlights").find("div").each(function(){
divsHTML.push($(this).html());
});
var position = -1;
!function loop() {
position = (position + 1) % divsHTML.length;
$highlights.html(divsHTML[position])
.fadeIn(1000)
.delay(1000)
.fadeOut(1000,loop);
}();
});
#highlights, #highlights-mobile {
background-color: #E8E8E8;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
position: relative;
display: block;
box-sizing: border-box;
overflow: auto;
text-align: center;
margin-bottom: 20px;
}
#highlights h4, #highlights-mobile h4 {
text-align: center;
font-weight: bold;
padding: 0;
margin: 0;
font-size: 1.2em;
}
#highlights-mobile {
padding: 10px;
}
#highlights-mobile a, #highlights a {
color: #444;
text-decoration: none;
}
#highlights div {
text-align: center;
padding: 10px;
border-right: 1px solid #CDCDCD;
color: #444;
overflow: auto;
display: inline-block;
}
#media (min-width: 768px) {
#highlights {
display: block;
}
#highlights div:last-child {
border-right: none;
}
}
#media (min-width: 768px) {
#highlights div {
text-align: center;
padding: 10px;
border-right: 1px solid #CDCDCD;
color: #444;
overflow: auto;
display: inline-block;
}
#highlights div:last-child {
border-right: none;
}
#highlights h4 {
text-align: center;
font-weight: bold;
padding: 0;
margin: 0;
font-size: 1.2em;
}
#highlights a {
color: #444;
text-decoration: none;
}
#highlights-mobile {
display: none;
}
}
#media (max-width: 767px) {
#highlights {
display: none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="highlights-mobile">
<div style="display: block;">
</div>
</div>
<div id="highlights">
<div>
<h4>Professionally refurbished</h4>Old school gear, good as new
</div>
<div>
<h4>Free shipping</h4>On orders over $250, nation wide
</div>
<div>
<h4>100% happiness guarantee</h4>Easy returns and a 60 day warranty
</div>
<div>
<h4>5% off your order</h4>When you pay with Bitcoin
</div>
</div>