Silhouette a PNG image using CSS - css

Anyone know of a way that I can get CSS to make a PNG image with transparency look completely blacked out like a silhouette?
In other words-
Going from something like this:
To this:
It's for a lot of images which is why I'd like to avoid doing it via Photoshop.

You can apply to the image style like filter: contrast(0%) brightness(50%) to get a silhouette. Do not forget prefixes.

I don't see how it could be done with pure css. Javascript might be able to acheive it but you may consider using server side programming instead. With php you could make a duplicate of your original png on the server and replace the non-transparent pixels with a single color. It would be similar to a watermarking function.

I tried this code that uses a canvas, maybe you could refine it especially on lighter pixel inside the apple
<img id="canvasSource" src="apple.jpg" />
<br />
<canvas id="area" width="264" height="282"></canvas>
<!-- Javascript Code -->
<script type="text/javascript">
window.onload = function() {
var canvas = document.getElementById("area");
var context = canvas.getContext("2d");
var image = document.getElementById("canvasSource");
context.drawImage(image, 0, 0);
var imgd = context.getImageData(0, 0, 264, 282);
var pix = imgd.data;
var blackpixel = 21;
for (var i = 0, n = pix.length; i < n; i += 4) {
//console.log(pix[i], pix[i+1], pix[i+2]);
if (i > 3) {
if ((Math.abs(pix[i-3] - pix[i]) > 10) &&
(Math.abs(pix[i-2] - pix[i+1]) > 10) &&
(Math.abs(pix[i-1] - pix[i+2]) > 10)
) {
pix[i ] = blackpixel;
pix[i+1] = blackpixel;
pix[i+2] = blackpixel;
}
}
else {
if (pix[i] < 250 && pix[i+1] < 250 && pix[i+2] < 250) {
pix[i ] = blackpixel;
pix[i+1] = blackpixel;
pix[i+2] = blackpixel;
}
}
}
context.putImageData(imgd, 0, 0);
};
</script>

Nowdays, filter combined to mix-blend-mode could do too :
span {/* to be used to lay the 'blender mask' over img */
position: relative;
display: inline-block;
overflow:hidden;
}
span img {
display: block;/* erase gap */
max-width:45vw;
filter: contrast(150%);
}
span + span img {
filter: contrast(120%) saturate(0%);/* saturate(0%) is similar to grayscale(100%) */
}
span:before {
content: '';
z-index: 1;
height: 100%;
background: white;
position: absolute;
top: 0;
width: 100%;
display: block;
filter: contrast(10000%) brightness(0) saturate(100%) grayscale(100%);
mix-blend-mode: color-burn;/* bake it to black */
animation : span 2s infinite alternate;
}
#keyframes span {
from{
transform:translate(-100%,0)
}
25%,50% {
transform:translate(0,0);
}
to{
transform:translate(100%,0)
}
}
<span><img src="https://i.stack.imgur.com/somZ7.jpg"/></span>
<span><img src="https://i.stack.imgur.com/somZ7.jpg"/></span>

Related

set width and height of an image after transform: rotate

i have a div with width: 190px and height: 260px, i assign img tag on that div, when i upload an image that shows how the image before, after that i rotate the image but the width and height of the image didnt change like the div, i have used inherit, everything about position and display, but no good at all..
I have figured out an automated way as below:
First, I am getting natural height and width of the image (from onload trigger):
var naturalWidth = event.currentTarget.naturalWidth
var naturalHeight = event.currentTarget.naturalHeight
Then I am computing a transform scale using aspect-ratio and generating transform style as below (pseudo-code):
For 90deg (y-shift):
const scale = naturalWidth > naturalHeight ? naturalHeight / naturalWidth : 1;
const yshift = -100 * scale;
const style = `transform:rotate(90deg) translateY(${yshift}%) scale(${scale}); transform-origin: top left;`
For 270deg (x-shift):
const scale = naturalWidth > naturalHeight ? naturalHeight / naturalWidth : 1;
const xshift = -100 * scale;
const style = `transform:rotate(270deg) translateX(${xshift}%) scale(${scale}); transform-origin: top left;`
Hope this helps.
Inherit will not work.
Because you have to make the set the width of your image as the height of your parent. Then it will get completely resize in the parent element.
image-width = parent-height
Because after applying transform property width and height property will also get rotate in its respect.
Sol 1:
change the width of your image along with the transform property. (If it is variable then you can use the SCSS variables to assign the same values to the image-width and parent height.)
Sol 2:
This is not the perfect solution but will work in many cases. Add scale property to your transform property like this
transform: rotate(90deg) scale(.7);
Adjust the scale values according to you.
Hey,
Please Try this code.
var $=jQuery.noConflict();
$(document).ready(function(){
$('#RotateButton').click(function(){
$('.col').toggleClass("afterRot");
});
});
/* ----- IE Support CSS Script ----- */
var userAgent, ieReg, ie;
userAgent = window.navigator.userAgent;
ieReg = /msie|Trident.*rv[ :]*11\./gi;
ie = ieReg.test(userAgent);
if(ie) {
$(".col").each(function () {
var $container = $(this),
imgUrl = $container.find("img").prop("src");
if (imgUrl) {
$container.css("backgroundImage", 'url(' + imgUrl + ')').addClass("custom-object-fit");
}
});
}
body { padding: 0; margin: 0; }
.col { position: relative; display: block; width:100vh; height: 100vh; }
.afterRot{ transform: rotate(90deg); object-fit: cover; }
.col img { position: absolute; top: 0; left: 0; right: 0; width: 100%; height: 100%; object-fit: cover; }
.custom-object-fit { position: relative; background-size: cover; background-position: center center; }
.custom-object-fit img { opacity: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mob">
<button type="button" id="RotateButton"> Rotate </button>
<div class="col">
<img class="nor" id="rowImg" src="https://cdn-images-1.medium.com/max/1600/1*tSyuv3ZRCfsSD5aXB7v8DQ.png">
</div>
</div>
I think this is because you are not removing the class already associated with the Image. Try adding this to your button
$(document).ready(function(){
$('#RotateButton').click(function(){
$('#rowImg').removeClass("normalx").addClass("afterRot");
});
});
for a css like
.col {
width:260px;
height:190px:
border: solid 1px #6c757d;
padding: 10px;
}
.nor{
width:250px;
height:150px;
}
.afterRot{
width:inherit;
transform: rotate(90deg);
}
I have a sample here

transition for translateY(0) working, but not translateY(-50px)

I'm having some trouble with a transition on a transform. I'm making a tic-tac-toe game like in the freecodecamp front-end challenges: https://codepen.io/freeCodeCamp/full/KzXQgy.
I've been able to create most layout things no problem, but am having an issue with my transition on a div that shows which players' turn it is after hitting the reset button. Right now I'm just working on two player mode, so I click two players, then X or O, and then the tic-tac-toe board shows up and a div transform: translateY(-50px) to indicate whether it's Player 1 or Player 2's turn (based on a random number variable I set up). The first time through the div transition's perfectly. Then I hit the Reset All div and it takes me back to the beginning to choose how many players again. And the div transitions the transform: translateY(0) perfectly back to it's starting position. Where I'm struggling is, now when I cycle through the options again, if it's Player 1 or Player 2's turn again, the transition never happens and the div just transforms -50px up with the translateY.
I've tried everything I could think of, JS setting up the transition, resetting the transition, moving the transition to be on different classes, adding and removing a class that only has a transition on it. Can't figure it out, but the weird thing is, whenever I hit the "Reset All", the transform transitions back to 0px normally. Here's my codepen: https://codepen.io/rorschach1234/pen/dZMaJg?editors=0111. I know it's still very rough, but just can't figure out this transition problem. Really appreciate any help. Thanks everyone!
My relevant Html:
<div class="container">
<div class="turns">
<div class="turns__left turns__box"></div>
<div class="turns__right turns__box"></div>
</div>
</div>
My relevant CSS:
.turns {
width: 100%;
display: flex;
position: absolute;
justify-content: space-around;
top: 0;
left: 0;
z-index: -1;
&__box {
width: 40%;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 1.3em;
font-family: sans-serif;
transition: transform 1s .3s ease;
}
&__left {
background-color: $color-turn-left;
//transition: transform 1s .3s ease;
}
&__right {
background-color: $color-turn-right;
//transition: transform 1s .3s ease;
}
}
My Javascript:
let numOfPlayers = document.querySelectorAll(".player .choices h2");
let playerScreen = document.querySelector(".player");
let markerScreen = document.querySelector(".markers");
let singlePlayer = true;
let backBtn = document.querySelector(".markers__back");
let gameScreen = document.querySelector(".game");
let playerOne; let playerTwo; let activePlayer;
let turnBoxes = document.querySelectorAll(".turns__box");
let resetBtn = document.querySelector(".scoreboard__reset");
game();
function game() {
playerModeSelection();
markerSelection();
}
function boardChange(active, inactive) {
inactive.style.opacity = "0";
inactive.style.zIndex = "0";
active.style.opacity = "1";
active.style.zIndex = "1";
}
//One or Two player Selection & transition to Marker Selector
function playerModeSelection() {
for (let i = 0; i < numOfPlayers.length; i++) {
numOfPlayers[i].addEventListener("click", function() {
if(i === 1) {
singlePlayer = false;
}
boardChange(markerScreen, playerScreen);
})
}
}
function markerSelection() {
//Back Button Functionality
backBtn.addEventListener("click", function() {
boardChange(playerScreen, markerScreen);
})
//Listen for choice of X or O
for (let i = 0; i < markers.length; i ++) {
markers[i].addEventListener("click", function() {
boardChange(gameScreen, markerScreen);
if (i === 1) {
playerArr = ["O", "X"];
}
//Starts Two Player Game; Here begin is the function that calls transition
if(!singlePlayer) {
twoPlayerMode();
}
})
}
}
function twoPlayerMode() {
activePlayer = Math.floor(Math.random() * 2);
turnBoxes[activePlayer].textContent = "Go Player " + (activePlayer + 1) + "!";
turnBoxes[activePlayer].style.transform = "translateY(-50px)";
resetBtn.addEventListener("click", function() {
boardChange(playerScreen, gameScreen);
turnBoxes[activePlayer].style.transform = "translateY(0px)";
})
}

Blurry image after scale in Safari and Chrome

I have a big image as background-image, and I reduce the size on scroll, and in the same time I modify the background-position too.
Unfortunately I found problems in Chrome and Safari. In these browsers as soon as I start to scroll the image become blurry.
I tried many solutions for that problem, but no luck. Do you have idea what's wrong, or an other method what can help to achieve the same effect?
JS
function promo_scroll() {
var current_scroll = jQuery(window).scrollTop();
var scale = 5;
var window_height = jQuery(window).height();
var window_width = jQuery(window).width();
var correction = jQuery('#header-wrapper').height()-500;
if(scale*((1-(current_scroll/window_height))) > 1 && (window_width/window_height >= 198/119)) {
jQuery('#custom-header').removeAttr('data-top');
jQuery('.container').css({
'position' : 'fixed',
'display' : 'block',
'top': 0,
'left': 0,
'transform' : 'scale(' + scale*((1-(current_scroll/window_height))) + ')',
});
jQuery('.container:not(.content)').css('background-position', '0 ' + correction + 'px');
} else if(window_width/window_height >= 198/119) {
if (typeof jQuery('#custom-header').attr('data-top') == 'undefined'){
jQuery('#custom-header').attr('data-top',jQuery('#custom-header').offset().top);
jQuery('#content-wrapper').css('padding-top',jQuery('#custom-header').offset().top);
}
jQuery('.container').css({
top : jQuery('#custom-header').attr('data-top')-current_scroll,
'transform' : 'scale(1)',
});
}
else{
jQuery('#custom-header').removeAttr('data-top');
jQuery('#content-wrapper').css('padding-top',0);
jQuery('.container').css({
'background-position': 'center top',
'position' : 'absolute',
'top': 0,
'left': 0,
'transform' : 'scale(1)',
});
jQuery('.container.content').css({
'position' : 'absolute'
});
}
}
jQuery(document).on('click','#custom-header', function(){
jQuery('html, body').animate({'scrollTop': jQuery('.l-grid-row').offset().top - jQuery('#main-header').outerHeight()},2500);
});
jQuery(document).ready(function(){
promo_scroll();
});
jQuery(window).on('scroll', function(){
jQuery('.container.content')[0].style.setProperty('background-position', jQuery(window).scrollTop() + 'px 50%', 'important');
promo_scroll();
});
jQuery(window).on('resize', function(){
jQuery('#custom-header').removeAttr('data-top');
promo_scroll();
});
CSS
body {
-webkit-font-smoothing: antialiased;
}
.container {
height: 100%;
width: 100%;
z-index: 6;
will-change: transform;
filter: none;
-webkit-filter: blur(0px);
-moz-filter: blur(0px);
-ms-filter: blur(0px);
filter:progid:DXImageTransform.Microsoft.Blur(PixelRadius='0');
}
.container.content{
z-index: 5;
background-image:url('http://i.imgur.com/f68DPZG.jpg');
background-position: left center;
background-repeat: repeat-x;
}
#header-wrapper {
display: none;
}
#media screen and (min-width: 767px) {
#header-wrapper {
display: block;
}
}
#media screen and (min-aspect-ratio: 198/119) {
.container {
-webkit-transform: scale(5);
-moz-transform: scale(5);
transform: scale(5);
background-size: 100% auto !important;
background-position: center center !important;
}
}
.spacing {
height: 2000px;
}
HTML
<div id="header-wrapper" data-full-height-header="true">
<div id="custom-header" class="container"></div>
<div class="container content"></div>
</div>
<div class="spacing">
</div>
The effect is visible only with a specific aspect ratio, so please check the link in full screen: https://jsfiddle.net/4eod1ng5/3/embedded/#Result
Update: After several testing it looks like the problem occurs only in OSX (Safari and Chrome)
Update 2: After I updated my chrome to 51 in linux the problem appeared.
unfortunately your fiddle does not work well for me, i can see some kind of weirdness, but i cannot run the fiddle when i edit it. however, running the code in my head:
you are using scale in combination with a blur effect. when you use scale 5, it will not re-initialize the effect, but only scale up the object. i would try starting with a big size (width + height = 500%) and rather scaling it down (scale < 1) than up.
you can also try transforming the container instead of the object with the background image. that helped for me occasionaly when dealing with problems like this.
I tried the jsFidle. the problem I see here is because the images are low resolution, try to use higher resolutions images

Set animated html5 canvas as the background without interacting with other elements?

I got the canvas working, I'm having issues trying to position it.
Specifically I want to implement them to the same effect as:
html {
background: url(back.jpg) no-repeat center center fixed;
background-size: cover;
}
for static images. Basically no interaction with other elements, and positioned as low as possible with regards to the stacking context. Additionally, I'd like to have the canvas background as compartmentalized / as segmented as possible from the rest of the code.
By segmented, I mean something like this:
<body>
<div id="backgroundContainer">
<canvas id="myCanvas"></canvas>
</div>
<div id="everythingElseContainer">
....
</div>
<script src="canvasAnimation.js"></script>
</body>
or this:
<body>
<div id="container">
<canvas id="myCanvas"></canvas>
<div id="everythingElse">
....
</div>
</div>
<script src="canvasAnimation.js"></script>
</body>
to minimize the possibility of css conflicts.
var WIDTH;
var HEIGHT;
var canvas;
var con;
var g;
var pxs = new Array();
var rint = 60;
$(document).ready(function(){
WIDTH = window.innerWidth;
HEIGHT = window.innerHeight;
canvas = document.getElementById('canvas');
$(canvas).attr('width', WIDTH).attr('height',HEIGHT);
con = canvas.getContext('2d');
for(var i = 0; i < 100; i++) {
pxs[i] = new Circle();
pxs[i].reset();
}
setInterval(draw,rint);
});
function draw() {
con.clearRect(0,0,WIDTH,HEIGHT);
for(var i = 0; i < pxs.length; i++) {
pxs[i].fade();
pxs[i].move();
pxs[i].draw();
}
}
function Circle() {
this.s = {ttl:8000, xmax:5, ymax:2, rmax:10, rt:1, xdef:960, ydef:540, xdrift:4, ydrift: 4, random:true, blink:true};
this.reset = function() {
this.x = (this.s.random ? WIDTH*Math.random() : this.s.xdef);
this.y = (this.s.random ? HEIGHT*Math.random() : this.s.ydef);
this.r = ((this.s.rmax-1)*Math.random()) + 1;
this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
this.hl = (this.s.ttl/rint)*(this.r/this.s.rmax);
this.rt = Math.random()*this.hl;
this.s.rt = Math.random()+1;
this.stop = Math.random()*.2+.4;
this.s.xdrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
this.s.ydrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
}
this.fade = function() {
this.rt += this.s.rt;
}
this.draw = function() {
if(this.s.blink && (this.rt <= 0 || this.rt >= this.hl)) this.s.rt = this.s.rt*-1;
else if(this.rt >= this.hl) this.reset();
var newo = 1-(this.rt/this.hl);
con.beginPath();
con.arc(this.x,this.y,this.r,0,Math.PI*2,true);
con.closePath();
var cr = this.r*newo;
g = con.createRadialGradient(this.x,this.y,0,this.x,this.y,(cr <= 0 ? 1 : cr));
g.addColorStop(0.0, 'rgba(255,255,255,'+newo+')');
g.addColorStop(this.stop, 'rgba(77,101,181,'+(newo*.6)+')');
g.addColorStop(1.0, 'rgba(77,101,181,0)');
con.fillStyle = g;
con.fill();
}
this.move = function() {
this.x += (this.rt/this.hl)*this.dx;
this.y += (this.rt/this.hl)*this.dy;
if(this.x > WIDTH || this.x < 0) this.dx *= -1;
if(this.y > HEIGHT || this.y < 0) this.dy *= -1;
}
this.getX = function() { return this.x; }
this.getY = function() { return this.y; }
}
html, body, div, button, canvas, .containr {
padding: 0;
border: none;
margin: 0;
}
html, body, .containr{
height: 100%;
width: 100%;
background: none;
}
html, body {
font-size: 13px;
text-decoration: none;
font-family: Verdana, Geneva, sans-serif !important;
}
button {
transition: all 0.24s ease;
}
h1 {
font-size: 4rem;
}
button {
font-size: 5.6rem;
}
#pixie {
position:fixed;
z-index: 0;
background: black;
}
.containr>div {
background: blue;
}
.containr {
overflow:hidden;
color: #ffffff;
z-index: 9;
font-size: 256%;
white-space: nowrap;
display: flex;
flex-flow: column nowrap;
justify-content: space-around;
align-items: center;
align-content: center;
}
.btnz {
margin-left: 2.4%;
margin-right: 2.4%;
background: #ffffff;
background: rgba(0, 0, 0, .36);
text-shadow: 1px 1px 3px #000;
padding: 2rem;
}
.btnz:hover {
background: #3cb0fd;
text-shadow: none;
text-decoration: none;
}
/* Outline Out */
.hvr {
display: inline-block;
vertical-align: middle;
-webkit-transform: translateZ(0);
transform: translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-moz-osx-font-smoothing: grayscale;
position: relative;
}
.hvr:before {
content: '';
position: absolute;
border: #e1e1e1 solid 5px;
top: -4px;
right: -4px;
bottom: -4px;
left: -4px;
-webkit-transition-duration: 0.3s;
transition-duration: 0.3s;
-webkit-transition-property: top, right, bottom, left;
transition-property: top, right, bottom, left;
}
.hvr:hover:before, .hvr:focus:before, .hvr:active:before {
top: -18px;
right: -18px;
bottom: -18px;
left: -18px;
border: #ffffff solid 8px;
}
<!doctype html>
<html lang="en">
<head datetime="2015-10-31">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="containr">
<canvas id="canvas"></canvas>
<div>
<h1>Main Title</h1>
</div>
<div>
<button class="btnz hvr">
Button Butt
</button>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="js.js"></script>
</body>
</html>
To move objects down in the visual order use the CSS styling z-index smaller numbers move the element down under other elements, higher numbers bring it up.See MDN z-index for more info.
To set the background of an element to a canvas use
element.style.background= "url(" + canvas.toDataURL() + ")";
To isolate of compartmentalize some code the easiest way is to wrap it in a anonymous function and call it. Everything inside it is isolated. Use 'use strict' directive to ensure you do not accidentally create global scoped variables.
A normal anonymous function does nothing and can not be used.
function(){ console.log(42); }; // does nothing
But if you wrap it in () and then add the function call tokens to the end ( ) you can call it like any function.
(function(){ console.log(42); })(); // send the meaning of life,
// the universe, and everything
// to the console.
The function below wraps up a and nothing can get access to a outside the anonymous function.
(function(){
var a = 1;
})();
But you can easily forget to put var in front of a variable making the variable visible to the entire page.
(function(){
var a = 1;
outThere = 2; // Oh no this is has been placed in
// global scope because it is missing
// the var token.
})();
To stop this use the 'use strict' directive.
(function(){
"use strict"; // this must be the very first line of the function
var a = 1;
outThere = 2; // this will cause the javascript to throw a
// ReferenceError: outThere is not defined
})();
It throws an error and stop the function from running but at least you will know that you have a leak.
Everything inside the anonymous function will manage itself. Deleting itself when not needed any more. Or remaining in memory if the Javascript engine holds an internal reference.
The next function starts up and calls its own function doSomething then exits and is deleted completely including the big array.
(function(){
var bigArray = new Array(100000000);
function doSomething(){
console.log("Whats up?");
}
doSomething();
})();
The next one will create a big array and hold that array in memory for 10 seconds (lifeTime). This is because the setTimeout has given the javascript engine an internal reference to doSomething. As long as that reference exists the bigArray will remain (because of closure). After the timeout the reference his no longer need and thus disposed causing all associated referances to go as well and thus disappear. All done via the magic of garbage collection.
Info on Clouser
Info on Garbage collection MDN is out of date but I am sure a quick search on StackOverflow will help.
(function(){
var bigArray = new Array(100000000);
function doSomething(){
console.log("Big Array has had its time.");
}
setTimeout(doSomething,10000);
})();
Attaching an object to items outside the anonymous function scope will expose data in that object to the global scope.
The next function adds a property to a DOM element. This is visible to the global scope and also means that the lifetime of the function will be as long as that element exists.
(function(){
function Info(){
... create info ..
}
var element = document.getElementById("thisOutsideWorld");
var importantPrivateInfo = new Info();
element.keepThis = importantPrivateInfo;
})();
But this does not apply to primitive types as they are copied not referenced. These are Numbers, Strings, Booleans , Undefined, Null...
So to set the background to a canvas via a compartmentalized function see the following function
(function(){
'use strict';
var myCanvas = document.createElement("canvas");
myCanvas .width = 1024;
myCanvas .height =1024;
var ctx = canvas.getContext("2d");
// toDo
// draw the stuff you want.
var el = document.getElementById("myElement");
if(el !== null){
el.style.background = "url("+canvas.toDataURL()+")";
}
// all done
})(); // once run it will delete the canvas and ctx and leave only the copied dataURL
You may think that this exposes the canvas. But it is safe as the canvas is converted to a string and strings are copied not referenced.
If you need to keep the canvas for some period then use a timer to create an internal reference to the anonymous function
The following function will create a canvas and update it every second for 100 seconds. After that it will be deleted and completely gone.
(function(){
'use strict';
var myCanvas = document.createElement("canvas");
myCanvas .width = 1024;
myCanvas .height =1024;
var lifeCounter = 0;
var ctx = canvas.getContext("2d");
// toDo
// draw the stuff you want.
var el = document.getElementById("myElement");
function update(){
// draw stuff on the canvas
if(el !== null){
el.style.background = "url("+canvas.toDataURL()+")";
}
lifeCounter += 1;
if(lifeCounter < 100){
setTimeout(update,1000);
}
}
update(); //start the updates
// all done
})();
Hope this helps.

css: float blocks to occupy all free space

I'm trying to make an "image mosaic" that consists mostly of images of the same size, and some of them the double height.
They all should align neatly like this:
To make automatic generation of those mosaic as easy as possible, I thought floating them would be the best option. Unfortunately, the big block causes the following ones to flow behind it, but not before:
What can I do - apart from manually positioning them - to get the images to the place I want, and still have it easy to automatically create likewise layouts?
The code I'm currently using is :
FIDDLE
HTML :
<div class="frame">
<div id="p11" class="img">1.1</div>
<div id="p12" class="img h2">1.2</div>
<div id="p13" class="img">1.3</div>
<div id="p21" class="img">2.1</div>
<div id="p22" class="img">2.2</div>
</div>
CSS :
.frame {
background-color: blue;
border: 5px solid black;
width: 670px;
}
.img {
width: 200px;
height: 125px;
background-color: white;
border: 1px solid black;
float: left;
margin: 10px;
}
.h2 {
height: 272px;
}
You need to use Javascript to achieve this effect, I had to do that once and I used http://masonry.desandro.com/ -- worked well!
Pure CSS Solution
Tested in Firefox, IE8+ (IE7 looks like it would need to be targeted to add a top margin added to 2.1 because it overlaps 1.1). See fiddle. This assumes .h2 is the middle div (as your example). If left most div it should not need any change. If right most, you would need to expand the negative margin to also include the third div following.
.h2 + div {
float: right;
margin: 10px 14px 10px 0; /*14px I believe also has to do with borders */
}
.h2 + div + div {
margin-left: -434px; /*need to account for borders*/
clear: right;
}
You can use a column layout like this:
http://jsfiddle.net/KKUZL/
I don't know if that will conflict with your automation process though....
I realize this is not a CSS-only solution, but for what it's worth (JSFiddle):
HTML:
<div id='container'></div>
CSS:
html, body {
margin:0px;
padding:0px;
height:100%;
}
body {
background-color:#def;
}
#container {
margin:0px auto;
width:635px;
min-height:100%;
background-color:#fff;
box-shadow:0px 0px 5px #888;
box-sizing:border-box;
overflow:auto;
}
.widget {
float:left;
box-sizing:border-box;
padding:10px 10px 0px 0px;
}
.widget > div{
height:100%;
box-sizing:border-box;
color:#fff;
font-size:3em;
text-align:center;
padding:.5em;
overflow:hidden;
}
.widget > div:hover {
background-color:purple !important;
}
JS:
////////////////////////////////////////
// ASSUMPTIONS
//
var TWO_COLUMN_WIDGET_COUNT = 1;
var ONE_COLUMN_WIDGET_COUNT = 15;
var NUMBER_OF_COLUMNS = 2;
////////////////////////////////////////
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var colorFactory = (function () {
var colors = [
'#CC9A17',
'#9B2C16',
'#1A8B41',
'#D97114',
'#3B9EE6'];
var index = 0;
return function () {
if (index > 4) {
index = 0;
}
return colors[index++];
}
})();
function widgetFactory(columnSpan) {
return {
'height': rand(10, 30) * 10,
'width': 100 * columnSpan / NUMBER_OF_COLUMNS,
'columnSpan': columnSpan,
'color': colorFactory()
}
}
function getWidgets() {
var widgets = [];
for (var i = 0; i < TWO_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(2));
}
for (var i = 0; i < ONE_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(1));
}
return widgets;
}
function getHighestOffset(offsets){
}
function getHighestSlot(offsets, numOfColumns){
}
$(document).ready(function () {
var container = $('#container');
var widgets = getWidgets();
var col1 = Math.floor(container[0].offsetLeft);
var col2 = Math.floor(container[0].clientWidth / 2 + container[0].offsetLeft);
var offsets = {};
offsets[col1] = 0;
offsets[col2] = 0;
var newLine = true;
for (var i = 0; i < widgets.length; i++) {
var w = widgets[i];
var marginTop = 0;
if (offsets[col1] < offsets[col2]) {
marginTop = (offsets[col2] - offsets[col1]) * -1;
}
if(offsets[col1] <= offsets[col2] || w.columnSpan == 2){
newLine = true;
}
var margin = 'margin-top:' + marginTop + 'px;';
var height = 'height:' + w.height + 'px;';
var color = 'background-color:' + colorFactory() + ';';
var width = 'width:' + w.width + '%;';
var padding = newLine ? "padding-left:10px;" : "";
var component = $('<div class="widget" style="' + padding + margin + height + width + '"><div style="' + color + '">' + i + '</div></div>');
component.appendTo(container);
var c = component[0];
var index = 0;
var minOffset = null;
for(var p in offsets){
if(minOffset == null || offsets[p] < minOffset){
minOffset = offsets[p];
}
if(p == Math.floor(c.offsetLeft)){
index = 1;
}
if(index > 0 && index <= w.columnSpan){
offsets[p] = c.offsetTop + c.offsetHeight;
index++;
}
}
newLine = minOffset >= offsets[col1];
}
});

Resources