Clipping a responsive full width image - javascript

I have to clip an image which spans full width. The following things didnt work for me
clip: this requires position absolute so the block elements dont stack below
background-position: it doesnt clip properly when zoomed the clipped portion increases when zoom in and vice versa.
wrapper: the wrapper height is dependent on the browser width so its value should be dynamic.
I used js with setinterval 1 millisec. so that wrapper height is constantly updated. works perfect in all scenarios but setinterval is bad practice. so please suggest a cleaner way to implement this.
document.onreadystatechange = setInterval(function () {
if (document.readyState == "complete") {
brow_width = document.body.clientWidth;
var h1 = (brow_width/7);
document.getElementById("clip1").style.opacity = "1";
if(brow_width > 700){
document.getElementById("clip1").style.height= h1;
}
else{
document.getElementById("clip1").style.height= 110;
}
var h2 = (brow_width/33.33);
document.getElementById("clip2").style.opacity = "1";
if(brow_width > 700){
document.getElementById("clip2").style.height= h2;
document.getElementById("banner2").style.top= h2 - brow_width*0.35;
}
else{
document.getElementById("clip2").style.height= 21;
document.getElementById("banner2").style.top= -220;
}
}
},1);
<!--two different clips of the same image-->
<div id="clip1">
<img id="banner1" src="banner.jpg">
</div>
<div id="clip2">
<img id="banner2" src="banner.jpg">
</div>

Try this:
HTML
<div class="banner">
<div class="bannerImg"></div>
</div>
CSS
.banner {
position: relative;
padding-bottom: 15%;
}
.bannerImg {
background-image: url(...);
background-size: cover;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
(Also here: http://jsfiddle.net/N6mCw/)
The idea is to use the outer wrapper to crop the image. If you need to support IE<9 then instead of a background image you'll have to add an <img> tag within the inner div and remove the background-image CSS:
<div class="banner">
<div class="bannerImg">
<img src"…" />
</div>
</div>
Although… the best way to do this would be to actually crop the image to the correct aspect ratio beforehand!

Related

Resizing images of different aspect ratios to fit a div without stretching it

I'm making a portfolio website and I am trying to make a simple image browser. I have a container div with size relative to the size of the browser window. I want that div to be able to contain images of different aspect ratios and a caption of fixed height and the width relative to the width of the image. I don't want the div to stretch to contain the images, I want to resize the image (you can see what I mean in the picture below).
illustration of the problem here
I was trying to use javascript to calculate the size of the image, but failed, because I couldn't calculate the element's size before it is actually loaded. This is how I tried to do it (not thinking about the titlebar):
var divAspectRatio = containerDiv.offsetHeight/containerDiv.offsetWidth;
var imageAspectRatio = image.offsetHeight/image.offsetWidth;
if(divAspectRatio>imageAspectRatio){
image.style.height = content_in.offsetHeight;
}else{
image.style.width = content_in.offsetWidth;
}
captionDiv.style.width = image.offsetWidth;
How do I make it work?
If your background image is in a div element, add this to your css, inside the div block:
background-size: cover;
If it's in an img element, add this to your css, inside the img block:
object-fit: cover;
Try using this css element:
object-fit: cover
This way, your image will get resized to fit the containing box!
The desired layout needs some calculation as the placing of an image that has aspect ratio bigger than the aspect ratio of the container differs from one that doesn't. Also to note is that the caption area is required to be only as wide as the displayed image but has a fixed height.
The imgs are wrapped in an 'innerdiv' which will also contain the caption. On loading the image's aspect ratio is found and stored as a CSS variable. Other CSS variables are set up in advance - see the head of this snippet for those that can be chosen. Remaining calculations are done in CSS.
window.onload = function () {
const imgs = document.querySelectorAll('.container .innerdiv .img');
imgs.forEach(img => {
img.parentElement.style.setProperty('--imgratio', img.naturalWidth / img.naturalHeight);
img.parentElement.classList.add(( (img.naturalWidth / img.naturalHeight) > getComputedStyle(img).getPropertyValue("--containerratio") ) ? 'wider' : 'thinner');
});
}
* {
padding: 0;
margin: 0;
}
.container {
/* SET THE NEXT 4 VARIABLES TO WHAT YOU REQUIRE */
--unit: 1vmin; /* the basic unit - must be fixed e.g. vmin, px, ch not % */
--containerw: 40; /* width of a container in these units */
--containerratio: 1.5; /* the ratio of width to height */
--captionh: 4vmin; /* height of a caption including its units (which must be fixed e.g. vmin, px, em */
--containerh: calc(var(--containerw) / var(--containerratio));
display: inline-block;
width: calc(var(--containerw) * var(--unit));
height: calc(var(--containerh) * var(--unit));
position: relative;
border: solid;
}
.innerdiv {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
.innerdiv.thinner {
width: calc(var(--imgratio) * ((var(--containerh) * var(--unit)) - var(--captionh)));
height: 100%;
left: 50%;
transform: translateX(-50%);
}
.innerdiv.wider {
width: 100%;
height: calc((var(--containerw) / var(--imgratio)) * var(--unit) + var(--captionh));
top: 50%;
transform: translateY(-50%);
}
.img {
width: 100%;
height: auto;
}
.caption {
font-size: 2vmin;
background-color: yellow;
text-align: center;
width: 100%;
height: var(--captionh);
position: absolute;
top: calc(100% - var(--captionh));
left: 0;
}
<div class="container">
<div class="innerdiv">
<img class="img" src="https://picsum.photos/id/1016/200/300">
<div class="caption">CAPTION</div>
</div>
</div>
<div class="container">
<div class="innerdiv">
<img class="img" src="https://picsum.photos/id/1016/500/200">
<div class="caption">CAPTION</div>
</div>
</div>
<div class="container">
<div class="innerdiv">
<img class="img" src="https://picsum.photos/id/1016/300/300">
<div class="caption">CAPTION</div>
</div>
</div>

CSS/JS: mimic background-image cover using image element with known width and height

I am trying to create letterboxes for video thumbnails in css. Thumbnails can be any size but I want them to fit within a box with a fixed aspect ratio of 16:9. This is easy to accomplish if I use the background-image properties. See the example below:
.container {
background-color: gray;
position: relative;
width: 100%;
padding-top: 56.25%;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.container1 {
background-image: url("https://bulma.io/images/placeholders/640x480.png");
}
.container2 {
background-image: url("https://bulma.io/images/placeholders/720x240.png");
}
<div class="container container1">
</div>
<br/>
<div class="container container2">
</div>
However, using background-image introduces a few problems. I only want the background of .container to be gray while the thumbnail is loading, once it has loaded I want it to be black. I also want to replace the thumbnail url with a default thumbnail url if for some reason the thumbnail fails to load. I cannot think of a way to do this without being able to use the onload and onerror events of an actual image element.
Fortunately, since in my actual code I am fetching the thumbnail urls dynamically I can also return the width and height of a thumbnail so I know it before I try to load it. However, I cannot figure out how to convert the width and height of the thumbnail into the correct percent it needs to be to cover the center of the box the same way the first example does using background-image. See the example below:
let c1ThumbnailWidth = 640;
let c1ThumbnailHeight = 480;
let c2ThumbnailWidth = 720;
let c2ThumbnailHeight = 240;
$( document ).ready(function() {
$('.container1 img').css('left', 100 * (1 - (9 / 16) * (c1ThumbnailWidth / c1ThumbnailHeight)) / 2 + '%');
$('.container2 img').css('left', 100 * (1 - (9 / 16) * (c2ThumbnailWidth / c2ThumbnailHeight)) / 2 + '%');
$('.container img').one('load', function() {
$(this).parent().css('background-color', '#000');
});
$('.container img').on('error', function () {
$(this).attr('src', 'default.jpg');
});
});
.container {
background-color: gray;
position: relative;
width: 100%;
padding-top: 56.25%;
}
.container img {
position: absolute;
top: 0;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container container1">
<img src="https://bulma.io/images/placeholders/640x480.png">
</div>
<br/>
<div class="container container2">
<img src="https://bulma.io/images/placeholders/720x240.png">
</div>
How can I make the image element mimic the behavior of a background-image set to cover or alternatively how can I tell when a background-image has loaded or failed to load and adjust it accordingly?
Have you tried using CSS object-fit on the image element?
https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit

How to properly target this background image to get parallax effect?

So I have this image as a background for a "parallax-divider" div, which I wish to stay on the page as it is, but I would like to make the image scroll slower than other content in order to accomplish a parallax effect. I know that I'm targeting something wrong way, but can't figure out how to fix it. Only thing I get is to move the whole div up and down/stretching in a very undesireable way. Any opinions how to fix this?
Here's the Codepen: http://codepen.io/anon/pen/vxOYrQ
.section {
height: 300px;
background-color: blue;
}
.parallax-divider {
background: url('http://www.planwallpaper.com/static/images/Cool-Background-Wallpaper-Dekstop.jpg') top center no-repeat;
background-size: cover;
background-attachment: fixed;
height: 200px;
}
<div class="section"></div>
<div class="parallax-divider" id="parlx">
<div class="wrapper">
<div class="parallax-divider__image">
<h2>lorem ipsum</h2>
</div>
</div>
</div>
<div class="section"></div>
function parallax() {
var parlx = document.getElementById('parlx');
parlx.style.position = "relative";
parlx.style.top = -(window.pageYOffset / 8) + 'px';
}
window.addEventListener("scroll", parallax, false)
Use transform: translateY() instead of top property. Also set parallax elemen to position: absolute, width: 100% and it wont strech. Like so :
translate('+ (-(window.pageYOffset / 8)) + 'px';

Javascript Scrolling Parallax Positioning

I'm currently doing a javascript parallax page. I've managed to set the background image and 2 other pictures(#content,#content2).
When i scroll all the way down past my content and then to my content2, I want my webpage to end there. However I'm able to scroll down infinitely.
Can anyone please look at my code and tell me what i need to add or change so that my webpage ends and stops scrolling after content2.
Please note that my #image is my main background and the content and content2 are separate images that go over my background but i want my page and scrolling to stop at content2.
Code:
<style type="text/css">
* {
margin: 0px;
padding: 0px;
}
#image {
position: relative;
z-index: -1
}
#content {
height:690px;
width: 100%;
margin-top:-10px;
background:url(http:/chicago_bulls_wallpaper_backgrounds.jpg);
position: relative;
z-index: 1;
background-repeat: no-repeat;
background-position: center center;
}
#content2 {
top:710px;
height:570px;
width: 100%;
margin-top:-10px;
background:url(All.jpg);
position: relative;
z-index: 1;
background-repeat: no-repeat;
background-position: center center
}
</style>
<script type="text/javascript">
var ypos, image;
function parallex() {
ypos = window.pageYOffset;
image = document.getElementById('image');
image.style.top = ypos * 1 + 'px';
}
window.addEventListener('scroll', parallex);
</script>
<img id="image" src="black-glass.png" height="710px" width="100%" />
<div id="content"></div>
<div id="content2"></div>
It's because your parallax factor is 1, meaning that the background is moving exactly with the screen. Thus, the browser thinks that it always has room and can always afford to scroll down, which is actually a pretty hilarious bug.
If you were intending true parallax scrolling, set your factor to less than 1, like this:
image.style.top = ypos * 0.95 + 'px';
If you simply didn't want your background to move at all with the rest of the page, set the body's background to this image (as you already do with the divs), and set the background-attachment property to fixed - no JavaScript required.
Is something like this what you are wanting? I am not having a problem with infinite scrolling.
http://codepen.io/vinsongrant/pen/advzww
<img id="image" src="https://upload.wikimedia.org/wikipedia/commons/d/da/The_City_London.jpg" height="710px" width="100%" />
<div id="content">
<h1>Here is content 1</h1>
</div>
<div id="content2">
<h1>Here is content 2</h1>
</div>

How to put an img element behind a transparent img element?

I have two img elements and I want the first image.png to go behind the transparent image.png. I have tried a lot of different things (z-index, transparent background color, rgba background color, positioning absolute and relative, nesting one in a div, making them both divs). Right now i've been trying to use a transparent .png image. The image .png is actually behind it, but it still shows through it. Please help.
html:
<body>
<main class="site-wrapper">
<div class="carnival"></div>
<div id="images">
<img id="divbox" src="images/divbox.png">
<img id="clown1" src="images/clown1.png">
</div>
</main>
</body>
js: (i did the styles in js b/c I was interested in learning how to do it that way):
//styles
//divbox:
document.getElementById('divbox').style.display = "inline-block";
document.getElementById('divbox').style.transform = "skew(-2deg)";
document.getElementById('divbox').style.marginTop = "21%";
document.getElementById('divbox').style.marginLeft = "47.6%";
document.getElementById('divbox').style.height = "200px";
document.getElementById('divbox').style.width = "200px";
document.getElementById('divbox').style.border = "1px solid orange";
document.getElementById('divbox').style.position = "absolute";
document.getElementById('divbox').style.zIndex = "2";
//clown1:
document.getElementById('clown1').style.display = "inline-block";
document.getElementById('clown1').style.transform = "rotate(90deg)";
document.getElementById('clown1').style.marginTop = "21%";
document.getElementById('clown1').style.marginLeft = "53%";
document.getElementById('clown1').style.border = "1px solid green";
document.getElementById('clown1').style.position = "relative";
document.getElementById('clown1').style.zIndex = "1";
Thanks for any help, please let me know if I can answer questions.
UPDATE:
Sorry for not being clearer. I have now achieved getting the image behind the other image, but since the image ontop is transparent, the image behind is showing. How do I stop this?
Here is an example of what is happening:
http://oi61.tinypic.com/2mw9egx.jpg
Notice the orange border is ontop so it is definitely ontop.
UPDATE 2:
This should make it really clear what I want. Again sorry for the confusion:
http://oi59.tinypic.com/eamb0n.jpg
I would do something like the following jsFiddle: http://jsfiddle.net/7gdx48fu/. Might need to reload a couple times to see a good example of the overlay working.
Create a wrapper DIV for your two images. Set that wrapper DIV's to position: relative so we can use absolute positioning on one of the images it contains. By doing this we prevent the absolute positioned image from potentially aligning itself elsewhere in the page, like the upper left corner of the browser window.
Then, set the position of our overlay image, the transparent PNG, to position: absolute along with top: 0 and left: 0 to align it with the first images upper left corner.
You can do this without using z-index if you watch the order you include your images. Place the image you want behind the transparent PNG in the markup first followed by the transparent PNG.
<div class="img-container">
<img src="http://lorempixel.com/200/200/city/">
<img class="overlay" src="http://lorempixel.com/200/200/city">
</div>
.img-container {
position: relative;
}
.overlay {
position: absolute;
top: 0;
left: 0;
opacity: 0.25; /* using this to replicate the transparent PNG */
}
EDIT
The OP's requirements have changed to include how to prevent an image behind a transparent image from showing through the transparent image.
Here is an updated jsFiddle: http://jsfiddle.net/7gdx48fu/2/.
This approach I wrapped the transparent PNG in a wrapper DIV and set it's background color. I used white in my example but you may use any color.
<div class="img-container">
<img src="http://lorempixel.com/200/200/city/">
<div class="overlay">
<img src="http://lorempixel.com/200/200/city">
</div>
</div>
.img-container {
position: relative;
}
.overlay {
position: absolute;
top: 0;
left: 0;
background-color: white;
top: 15px; /* shifting overlay for illustrative purposes - not use case code */
left: 15px; /* shifting overlay for illustrative purposes - not use case code */
}
.overlay img {
opacity: 0.25; /* using this to replicate the transparent PNG */
}
Not perfect but I'm unsure of how else to proceed.
EDIT 2
It seems the OP wants to do a form of masking. You can do this with overflow: hidden.
I have updated the jsFiddle: http://jsfiddle.net/7gdx48fu/4/
In this updated answer I have kept the wrapper DIV and set it with a fixed width and height. Then applied overflow: hidden. What we are doing here is creating an invisible window that will only show content when it is within the dimensions of the window.
To have the image appear as if it is coming out of the base layer image simply adjust the position of the image inside the wrapper DIV. For the jsFiddle simply play with the value of top in .mask img.
This will need a little tweaking for the proper placement and size of the .mask DIV to fit your needs but hopefully points you in the right direction.
<div class="img-container">
<img src="http://lorempixel.com/200/200/city/">
<div class="mask">
<img src="http://lorempixel.com/200/50/city">
</div>
</div>
.img-container {
position: relative;
}
.mask {
position: absolute;
top: 25px;
left: 25px;
height: 100px;
width: 100px;
overflow: hidden;
border: 1px solid red; /* for illustrative purposes */
}
.mask img {
position: relative;
top: 25px;
}
Have you tried the css opacity property ?
#clown1{ opacity:0.3;}
make both images' position absolute instead of relative
for the above to work, some common ancestor (i.e. #images) must have a non-default position too (e.g. relative)
forget zIndex - all else being equal, the latter element will be "topmost"
put all the above in a CSS style sheet instead of in JS code!
Forgetting the other transformations and margins, etc, the core CSS that you need is:
#images {
position: relative;
}
#divbox, #clown1 {
position: absolute;
}
Put them both in a parent container. Make the parent have position: relative and put both images having position:absolute. That way they will stack.(Something like that that I didn't check The order of img's could be wrong - play around a bit.
CSS:
.parent > img.transparent {
position: absolute;
}
.parent > img {
position: absolute; opacity: 0.5
}
HTML:
<div class="parent" style="position:relative">
<img src="other.png" class="transparent"/>
<img src="transparent.gif"/>
</div>
Some more explanation: When you make a parent/ancestor element's position relative it means that its contents that are absolute will be relative to the parent and not to the whole window

Categories

Resources