Creating a 'Zoom' like dynamic gallery view in CSS/HTML - html

I have an application where I want to create a full sized HTML page for displaying on a Kiosk.
Javascript will change the number of images depending on how many people are interacting with the kiosk (this side is all handled).
I could have one image, it could be two, three, four, anything up to 7x7 = 49.
I want to create a layout that looks very similar in how 'Zoom' creates the gallery view.
For instance:
One image: would be 100% width and height of the page
Two images: would do 50% width/height, showing eachother side by side with letterboxing top and bottom of the page
Three images: two on the top line, one on the bottom - with the bottom one horizontally centred
Four images: 2x2 grid
Five images: three on the top line, two on the bottom line
etc
Nine images: 3x3 grid
You get the picture!
I've spent a good few hours today trying to solve this. I don't really have working code to show any more as I have tried lots of options. I have tried pure CSS, jquery manipulating tables, utilities that create masonry galleries, etc. None seem to achieve what I want.
Does anyone have any bright ideas on how to make this happen?
It's running on Chrome in a controlled environment so don't need to worry about cross browser compatibility and can generally get away with using most options for technologies to get this to work.
Thanks

If you wanted the new people to come in at the bottom/left then grid would be the answer. But to get the bottom row centered we need to turn to flex.
As you will probably be using JS to insert or remove people you can calculate how many columns you need each time and reorganize the screen.
Here's a snippet showing the calculation. Change the number of divs in #container to see the effect. The aspect ratio for the person div is set in JS as variable personAspect. Currently set to 16:9 but can be altered as required.
<head>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#screen {
position: relative;
width: 100vw;
height: 100vh;
background-color: black;
overflow: hidden;
}
#container {
position: relative;
top: 50%;
margin: auto;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.person {
background-image: url(https://i.stack.imgur.com/ju8HY.jpg);
background-size: cover;
background-repeat: no-repeat;
}
</style>
<style id="person">
</style>
</head>
<div id="screen" >
<div id="container">
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
</div>
</div>
<script>
const personAspect = 16/9; /* SET TO WHAT YOU WANT IT TO BE FOR EACH PERSON DIV */
const maxCols = 7;
const screen = document.getElementById("screen");
const container = document.getElementById("container");
function reorganize() {
const people = container.querySelectorAll('.person');
const numPeople = people.length;
const screenAspect = window.innerWidth/window.innerHeight;
let cols = 1;
for (cols; cols <= maxCols; cols++) {
if (numPeople <= (cols * cols)) { break; }
}
let w = 0; //will be of the container in px
let h = 0; //will be height of the container in px
if (numPeople > (cols * (cols-1))) {// > OK for 5 and 6 not OK for 7
h = window.innerHeight;
w = h * personAspect;
} else {
w = window.innerWidth;
h = w / personAspect;
}
container.style.width = w + 'px';
document.getElementById('person').innerHTML = '.person {flex: 0 0 ' + (100/cols) + '%; height: ' + (h/cols) + 'px;}';
if (numPeople <= (cols * (cols-1))) {h = h- h/cols;}// for when last row is empty
container.style.marginTop = (- h)/2 + 'px';
}
reorganize();
window.onresize = reorganize;//not needed for final production but to make it easier to use the real window aspect ratio when developing
</script>
</body>

Related

How to add a tint to a background image with transparency in CSS

I have some content on a page that serves as a global background.
I put a sprite (div with background-image: url(...), changing frames by modifying background-position) on top of that using position: absolute. The sprite is a PNG with alpha-channel.
Now I'm trying to add some tint to that image (greenish or blueish or other).
I've studied the similar questions and apparently the only possible solutions are:
Create a div on top of the sprite with the desired color as its background-color, desired tint strength as opacity and the original sprite image as mask-image (and setting the mask-type: alpha). While it should work on paper, it doesn't in practice - this new div is just invisible :(
Use mix-blend-mode for the overlaying colored div and specify something like multiply or overlay. It produces perfect results as long as the global background is black. If it's something else - it gets included in the calculations and the overlay div modifies it as well, producing a tinted rectangle instead of tinted sprite...
Use SVG filter as described in an answer here: https://stackoverflow.com/a/30949302/306470 .
I didn't try this one yet, but it feels unnecessary complicated for this task. I'm concerned about the performance here too, will it slow down things a lot if there will be multiple tinted sprites on the screen at the same time? If anyone had experience with it - please comment here :)
Prepare a tinted version of the sprite using an invisible canvas. Sounds even more complicated, has a disadvantage of having to spend time to prepare the tinted version of the sprite, but should work as fast as the original sprite once it's prepared? Implementation should be pretty complicated though. Pure CSS solution would be much better...
Am I missing something? Are there any other options? Or should I go with #3 or #4?
Here is a working example of the outlined comment I left, hope it helps. I use a created div element to overlay on top of the image. Get the image elements position using boundingClientRect and this.width/this.height inside a for loop looping over the image elements. Set the overlay elements position to that of the image element being looped over and randomize a color using function with rgb setting alpha to 0.5.
let fgrp = document.getElementById("group");
let images = document.querySelectorAll(".imgs");
//function to randomize the RGB overlay color
function random() {
var o = Math.round,
r = Math.random,
s = 255;
return o(r() * s);
}
//function to randomize a margin for each image to show the overlay will snap to the image
function randomWidth() {
var n = Math.round,
ran = Math.random,
max = 400;
return n(ran() * max);
}
// loop through the img elements and create an overlay div element for each img element
for (let i = 0; i < images.length; i++) {
// load the images and get their wisth and height
images[i].onload = function() {
let width = this.width;
let height = this.height;
this.style.marginLeft = randomWidth() + "px";
// create the overlay element
let overlay = document.createElement("DIV");
// append the overlay element
fgrp.append(overlay);
// get the image elements top, left positions using `getBoundingClientRect()`
let rect = this.getBoundingClientRect();
// set the css for the overlay using the images height, width, left and top positions
// set position to absolute incase scrolling page, zindex to 2
overlay.style.cssText = "width: " + this.offsetWidth + "px; height: " + this.offsetHeight + "px; background-color: rgba(" + random() + ", " + random() + ", " + random() + ", 0.5); left: " + rect.left + "px; top: " + rect.top + "px; position: absolute; display: block; z-index: 2; cursor pointer;";
}
}
img {
margin: 50px 0;
display: block;
}
<div id="group">
<image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
<image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
<image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
</div>
Following the guide below, it is possible to at a colorful tint over a div/image using only CSS, like so:
<html>
<head>
<style>
.hero-image {
position: relative;
width: 100%;
}
.hero-image:after {
position: absolute;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, .5);
top: 0;
left: 0;
display: block;
content: "";
}
</style>
</head>
<body>
<div class="hero-image">
<img src="https://cdn.jpegmini.com/user/images/slider_puffin_before_mobile.jpg" alt="after tint" />
</div>
<div>
<img src="https://cdn.jpegmini.com/user/images/slider_puffin_before_mobile.jpg" alt="before tint" />
</div>
</body>
</html>
Since you are trying to place it on top of an absolute position image, as the guide says, add a z-index of 1 (for example) to the :after chunk.
Edit: It might need some tweaking on the width's percentage!
Source: https://ideabasekent.com/wiki/adding-image-overlay-tint-using-css

How to wrap content - including images - around a responsive CSS sidebar

Here's the layout I'm trying to achieve:
My content currently is a series of basic, block HTML elements (h[1-5], p, ul, etc.) contained in a div, and if possible I'd like to keep them that way. All of the images are inside their own p in order to responsively resize
I've been able to add a div style="float:right" to the top of the content which creates the sidebar and wraps "normal" text content around it - specifically the first paragraph in my diagram above. However, the img, which is set to 100% does not wrap, it flows below the sidebar.
So really, I want images to have one of two widths - either 100%-width(sidebar) if the top of the image "should be" above the bottom of the sidebar, or 100% if the top of the image is below the bottom of the sidebar.
I can of course manually set the width on an image when debugging a page, to a value less than 100%-width(sidebar) and it jumps right up into place, so clearly the browser knows what that size is to not "push" the image down below the sidebar...
Here's the actual page where I'd like to get this to work; note that the first image is below the sidebar:
https://adventuretaco.com/?p=3655&draftsforfriends=kIq7mVDhNtCSklITGCJs2HAcE9xuPX8d
additionally, here is the CSS and HTML that I currently have for the post content:
CSS
p {
margin: 0 0 1.25em 0;
}
ol, ul {
margin: 0 1.5em 1.25em 1.5em;
}
.full-width-container {
width: 100%;
}
.full-width-container img {
display: block;
margin-left: auto;
margin-right: auto;
overflow: hidden;
transition: 0.5s;
}
.full-width-container img.flickrPhoto {
display: block;
width: 100%;
margin-left: auto;
margin-right: auto;
overflow: hidden;
transition: 0.5s;
}
HTML
<div class="post-content">
<p>As you may recall, we'd just cancelled our flight home due to the unknowns of Covid-19, but were still in exploration mode as we entered the Valley of Fire State Park in southeastern Nevada.</p>
<p id="photoContainer132" class="full-width-container"><img id="photo132" class="flickrPhoto" src="https://live.staticflickr.com/65535/49714173358_d19b1c2e70_n.jpg" /></p>
<p>Our trip to the Valley of Fire was somewhat opportunistic to say the least. A year before this trip ever even crossed my mind, I'd seen a photo on Flickr that had caught my eye. Sharp as ever, I completely forgot to save the photo or a link to the photo <img src="https://www.tacomaworld.com/styles/default/my/smilies/annoyed_gaah.gif" />, but - luckily for me - the photo had been geotagged <em>and</em> I'd saved a point of interest in my Google Earth map of Nevada. I'd noticed that point as I'd planned this trip, and mapped out the route, excited to see what nature had in store. So yeah, apparently, I'm not <em>always</em> as dumb as I look. <img src="https://www.tacomaworld.com/styles/default/my/smilies/original/wink.png" /> In researching Valley of Fire, I also discovered a second hike -rumored to have petroglyphs - and since it was on our way to the main attraction, we decided to stop off there first.</p>
<p id="photoContainer133" class="full-width-container"><img id="photo133" class="flickrPhoto" src="https://live.staticflickr.com/65535/49715029457_a61cffc61b_n.jpg" /></p>
</div>
I think you first need to downsize a little your images, due to their size, it becomes a little difficult to manipulate them within the scope of what you would like to do. You can alter them inside the tag, or from the css file. Then after, you can use inside of that code a "float: left;" in the .full-width-container img, give it a margin that should put them side to side.
OK, so after a bunch more research, trial and error, I've come to the conclusion that the answer to this question is that it cannot be solved with CSS / layout alone.
In the end, incorporated Javascript to solve the problem. It's not perfect - if images have been downsized to flow around the sidebar, then when the browser window gets larger, they don't get larger as ideally as they could.
Here's where I ended up; working sample at (scroll down here to see the sidebar)
https://adventuretaco.com/hidden-valleys-secret-tinaja-mojave-east-5/#photoContainer190
// start shortly after page is rendered
setTimeout(resizeImagesForFacebookEmbed, 500);
function resizeImagesForFacebookEmbed() {
var tryAgain = true;
// find each of the elements that make up the post, and iterate through each of them
var content = jQuery('div.post-content').children().each(function () {
if (this.tagName.toLowerCase() == 'p') {
var firstChild = this.firstChild;
var firstElementChild = this.firstElementChild;
if (firstChild != null && firstChild == this.firstElementChild && firstElementChild.tagName.toLowerCase() == 'img') {
var pRect = this.getBoundingClientRect();
var imgRect = firstChild.getBoundingClientRect();
var difference = imgRect.top - pRect.top;
// if the image contained in the p is not at the top of the p, then make it smaller
// so it will fit next to the embed, which is 350px wide
if (difference > 25 || imgRect.width < (pRect.width - 400)) {
var sidebarLeft = document.getElementById("fbSidebar").getBoundingClientRect().left;
var imgLeft = firstChild.getBoundingClientRect().left;
var imgWidth = (sidebarLeft - imgLeft) * .95;
firstChild.style.width = imgWidth + "px";
tryAgain = false;
setTimeout(resizeImagesForFacebookEmbed, 1000);
} else {
// do nothing
}
}
}
});
if (tryAgain)
setTimeout(resizeImagesForFacebookEmbed, 1000);
}
var waitForFinalEvent = (function () {
var timers = {};
return function (callback, ms, uniqueId) {
if (!uniqueId) {
uniqueId = "Don't call this twice without a uniqueId";
}
if (timers[uniqueId]) {
clearTimeout(timers[uniqueId]);
}
timers[uniqueId] = setTimeout(callback, ms);
};
})();
// handle window resize event to re-layout images
jQuery(function () {
jQuery(window).resize(function () {
waitForFinalEvent(function () {
resizeImagesForFacebookEmbed();
}, 500, "atFbEmbedId"); // replace with a uniqueId for each use
});
});

Responsive Design: Is there a way to automatically enlarge and reduce my website to the height instead of the width of the window?

I have a website that has content. As an example it is 900px high and 1014px wide. On mobile phones etc. the size of the ad automatically adapts to the width of the screen and if there is an excess of height, the display simply scrolls. But I want it to adapt to the height instead of the width of the page/screen.
I want to do it this way because on most mobile devices my content is too long in height, which is a problem, and if it is a bit shorter in width, then it's not a problem because I would simply have space left and right.
Thanks in advance
Cyknos
Edith:
So here some Example Code (i'm not allowed to show the original Code):
HTML (Body):
<div class="content">
//here are some images, other divs and much more
</div>
CSS:
.content {
position: absolute;
left: 50%;
margin-left: -512px;
width: 1024px;
height: 910px;
}
Two examples to descripe how it is now:
If the Window/Screen has a size of 1200px width and only 800px in height, the overflow-down is only with scroll visible -> thats normal.
If the Windoe/Screen has a size of 900px width and 1000px height it would "zoom out" my page, so the hole content is Visible -> thats also normal.
My Goal:
My goal is, that if the height of the Window/Screen will become smaller as the height of the Content -> then the same thing should happen as normaly it does on example 2
Here is my solution (Example-Code):
var result = [];
var isFirefox = typeof InstallTrigger !== 'undefined';
var contentHeight = 800; //your content
function bodySizing() {
if(window.innerHeight < contentHeight) {
var diff = contentHeight-window.innerHeight;
var substractor = diff/contentHeight;
var scale = 1-substractor;
if(scale<1) { //only downsizing, no upsizing
$('body').css('zoom', scale);
$('body').css('-moz-transform', 'scale('+scale+')');
$('body').css('-o-transform', 'scale('+scale+')');
if(isFirefox) {
$('body').css("background-size", result[0]*scale+"px " + result[1]*scale + "px");
} else {
$('body').css("background-size", result[0]+"px " + result[1] + "px");
}
}
}
}
EDIT: Added FF-Fix

Is it possible to make even columns on this wordpress theme? Link provided with ids specified

Link for reference is here: http://www.roi-owa.com/
The sidebar column (on the right) is written like this...
#aside {
background: #ffffff;
width: 220px;
overflow: hidden;
}
The main content column (on the left) and wider....is written like this...
#content.alpha,
#content.beta {
width: 700px;
background-color: #ffffff;
background-image: none;
}
The problem is that with how this theme is written...the aside column isn't contained inside a floated container with the content div...so I might be stuck. I don't want to start rewriting theme files, I just want the right column to stretch down to the height of the #content div. Not sure if its possible.
Unfortunately I don't know of way for this to be done in pure CSS, since the columns know nothing about each other. However, some simple Jquery could be used.
The idea is to check the height of both and set the shorter one's height to the longer one's height. It should look something like this in jQuery:
var contentHeight = $("#content").outerHeight();
var asideHeight = $("#aside").outerHeight();
if ( contentHeight > asideHeight ) {
$("#aside").height( contentHeight );
}
else {
$("#content").height( asideHeight );
}

Scroll background image untill the end not further

I am working on a site and I don't want to repeat the background in the y direction.
I know how to do that.
But after the image I don't want background to becomes white or any other color.
I would like it to fix when it reaches that place or to let the background scroll slower then the rest of the site so I wont get to a white part.
Thanks a lot
I found this thread while I was looking for a solution to just this problem. I managed to write a short jQuery script adapting the hints given by Alex Morales.
With the following code, the background-image of the body scrolles down with the rest of the site until its bottom is reached. You can take a look at my homepage (http://blog.neonfoto.de) to see what it does.
$( window ).scroll( function(){
var ypos = $( window ).scrollTop(); //pixels the site is scrolled down
var visible = $( window ).height(); //visible pixels
const img_height = 1080; //replace with height of your image
var max_scroll = img_height - visible; //number of pixels of the image not visible at bottom
//change position of background-image as long as there is something not visible at the bottom
if ( max_scroll > ypos) {
$('body').css('background-position', "center -" + ypos + "px");
} else {
$('body').css('background-position', "center -" + max_scroll + "px");
}
});
This is actually the very first thing I did with JavaScript and JQuery, so any improvement would be great!
It's css3 so it's not super well supported, but I would look at the background-size property.
This is just off the top of my head but I think you will probably have to create a separate div containing the background image. If you place it in your markup before the main content and position the main content absolutely, it will sit behind the main content and at the top of the page. So:
CSS:
#background_div
{
background: url(images/some_image.png);
height: 600px;
width: 900px;
}
#main
{
height: 1200px;
width: 800px;
background: rgba(0, 0, 0, 0.25);
position: absolute;
top: 0;
}
HTML:
<div id="background_div"> </div>
Then what you do is you use javascript (I recommend jQuery) to detect the div's position on the screen.
jQuery:
This code grabbed from http://www.wduffy.co.uk/blog/keep-element-in-view-while-scrolling-using-jquery/
var $scrollingDiv = $("#background_div");
$(window).scroll(function(){
$scrollingDiv
.stop()
.animate({"marginTop": ($(window).scrollTop()) + "px"}, "slow" );
});