Keeping aspect ratio of image but cropping when hitting max/min height - css

I'm trying to make this image responsive that it will resize and keep it aspect ratio at all sizes. However above 650px, its height won't increase but will just crop the top and bottom to keep the ratio and not stretch. Also I want the image height won't go below 200px and just the left and right. I want image to always be center too. Here is what I have so far: https://jsfiddle.net/4q83mh41/
<div class="hero">
<img src="http://wpdevserver.x10host.com/wp-content/themes/wp/img/hero1.jpg">
</div>
.hero {
width: 100%;
min-height:200px;
max-height: 650px;
position: relative;
}
.hero img {
width: 100%;
height:auto;
min-height:200px;
overflow: hidden;
max-height: 650px;
position:aboslute;
}
Many thanks

By adding some javascript, the position of the image can be adjusted dynamically inside the .hero div. Additionally, CSS media queries can be used to keep the width of the image correct.
.hero {
width: 100%;
overflow: hidden;
max-height: 650px;
}
.hero img {
position: relative;
height: 200px;
width: auto;
}
#media (min-width:420px) {
.hero img {
width: 100%;
height: auto;
}
}
The javascript simply listens for resize events and adjusts the top and right properties of the relatively positioned image to keep it centered. Note that I'm using JQuery to manipulate the properties.
var heroresize = function() {
var aspect = 1800./858,
maxheight = 650,
minheight = 200,
width = $(".hero").width();
if(width < minheight*aspect) {
$(".hero img").css("right",(minheight*aspect - width)/2 + "px");
} else {
$(".hero img").css("right","0px");
}
if(width > maxheight*aspect) {
$(".hero img").css("top",(maxheight - width/aspect)/2 + "px");
} else {
$(".hero img").css("top","0px");
}
}
$(function(){
heroresize();
// remove if you don't need dynamic resizing
$(".hero").on("resize",heroresize);
});
The Javascript may cause some lag/stutter because resize events can be performance-intensive. If you don't need to worry about dynamic resizes, you can remove the indicated line.
I created a codepen you can play with here: http://codepen.io/regdoug/pen/azxVwd Note that the codepen has a max height of 350px because that allows you to see the effect without so much resizing.

Related

ScaleY a svg while followed by the below text divs

I need to change the height of a svg on mousewheel/scroll, but while this svg resizes, I need to make the text below follow this scaleY. I've tried implementing a position: relative but this does not work. How can I do that? Here's a PS of what I try to achieve.
Here's a PS of what I have now - images and text are just placeholder.
This is my relevant HTML code:
<div className="main_container">
<div className="main_container_inner">
<div className="img_container">
<img src={img_link} />
</div>
<div className="text_container">
<h1>fvdfv</h1>
<p>fvdfv</p>
</div>
</div>
</div>
This is my relevant CSS code:
.main_container{
display: block;
position: fixed;
width: 100vw;
}
body{
height: 400vh;
}
.main_container .main_container_inner{
display: inline-flex;
width: 33.33%;
flex-direction: column;
}
.main_container img{
width: 100%;
transform-origin: top;
}
This is what I have for now:
As you can see, when I change the scaleY value of the image, the text does not adjust to the new height.
The issue here is the flex containers do not have a setted height property.
So when you scale an image, it is quite hard to set its container height accordingly, so it "pushes" the other divs below. The image simply overflow its container.
I found a way anyway! Because I sticked (maybe for too long) on that weird challenge.
It requires a couple calculations.
I assumed you wish to scale up for the original height of the image to 100% of the viewport height. This assumption may be wrong... I this case, just play with those calculations. You have the example well commented below.
Another thing I noticed is you seem to use React. If so, I guess you should store the img height and its container height in the component state.
   I'm leaving that challenge to you ;)
// Get the elements
let main_container = document.querySelector(".main_container")
let imgContainer = document.querySelector(".img_container")
let img = document.querySelector(".img_container img")
// Some global variables to be filled when the image has fully loaded or on window resize
let viewportHeight, scrollHeight, scrollable, currentImgHeight, maxScale
// When the img has loaded...
function imgLoaded(){
// Get some dimentions
viewportHeight = window.innerHeight
scrollHeight = document.documentElement.scrollHeight
scrollable = scrollHeight-viewportHeight
// Calculate the maxScale for an img height == 100% of the viewport
currentImgHeight = img.getBoundingClientRect().height
maxScale = viewportHeight/currentImgHeight
// Set an initial height to the .img_container - Same as the img.
imgContainer.style.height = currentImgHeight+"px"
}
// If the image has already fully loaded (cache), else wait for the load event
if(img.complete){
imgLoaded()
}else{
img.addEventListener("load", imgLoaded)
}
// On window resize
window.onresize = function(){
img.style.transform = "scale(1)"
window.scrollTo(0,0)
imgLoaded()
}
// Scroll handler
function scrollHandler(){
// update the current img height value
currentImgHeight = img.getBoundingClientRect().height
// Calculate a new scale for the img -- The +1 is to avoid a negative value at the bottom of the page
let newScale = scrollable/(scrollable + 1 - document.documentElement.scrollTop)
// Apply the newScale if less or equal to maxScale
let scale = (newScale>maxScale)?maxScale:newScale
img.style.transform = `scaleY(${scale.toFixed(3)})`
// Adjust the img_container, so it pushes the div below
imgContainer.style.height = currentImgHeight+"px"
// Just for this demo...
console.log(imgContainer.style.height,scale.toFixed(3)+"% ")
}
// Add the event listener
document.addEventListener("scroll", scrollHandler)
/* Just for this demo... Styling the SO console which is in the way! */
.as-console{
background: transparent !important;
text-align: right;
}
.as-console-wrapper{
max-height: 1em !important;
border-top: 0 !important;
}
.as-console-row-code{
padding: 0 !important;
border: 0 !important;
}
/* added to your CSS */
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Your css unchanged */
.main_container {
display: block;
position: fixed;
width: 100vw;
}
body {
height: 400vh;
}
.main_container .main_container_inner {
display: inline-flex;
width: 33.33%;
flex-direction: column;
}
.main_container img {
width: 100%;
transform-origin: top;
}
<div class="main_container">
<div class="main_container_inner">
<div class="img_container">
<img src="https://via.placeholder.com/400" />
</div>
<div class="text_container">
<h1>fvdfv</h1>
<p>fvdfv</p>
</div>
</div>
</div>
Run in full screen mode! or CodePen

How to center an image with cover in css without using javascript

function set_bg_container_height() {
let e = document.getElementById("bg_container");
e.style.height = window.innerHeight + "px";
}
window.onresize = function() {
set_bg_container_height();
}
set_bg_container_height();
body {
margin: 0;
padding: 0;
}
#bg_container {
width: 100%;
height: 100%;
/* will be overruled by javascript */
}
#bg_image {
object-fit: cover;
width: 100%;
height: 100%;
}
<div id="bg_container">
<img id="bg_image" src="eyes1.jpg">
</div>
I want an image in the background just large enough that it always covers the window.
Without javascript I get:
Or other unwanted behaviour. Is it possible without using javascript?
You can also put background-position property in your css file which has value of x-axis and y-axis along with center you can do it like that background-position:center; or like background-position:x-axis y-axis or background-position:aSingleValueForBothAxis,
I sure hope this will solve your problem

How to insert an image in a DIV keeping the aspect ratio of the tags?

I made this code:
<div id="divImage" style="background-color: skyblue;height: 200px;">
<div style="background-color: red;width: 8%;height: 60px;margin-left: 20px; position: relative;top:50%;margin-right: auto;transform: translateY(-50%);"></div>
<div style="background-color: red;width: 8%;height: 60px;margin-right: 20px; position: relative;top:50%;margin-left: auto;transform: translateY(-150%);"></div>
</div>
I need to insert an image in the divImage with a width of 100%. For this, it is necessary that the divImage height is not fixed (height: 200px;). My intention is to make this divImage adapt to any screen size (in%).
You can force your box to keep an aspect ratio using its pseudo elements. Here the before element will always have a certain padding top which makes the box take up its height in relation to its width because the 100% in the equation always refers to the container's width.
.divImage {
&:before {
// Change this line to adjust the aspect ratio
// 1px / 1px will for example give you a square box.
// The first value refers to the height-part
padding-top: 5px / 10px * 100%;
content: "";
width: 1px;
margin-left: -1px;
float: left;
height: 0;
}
&:after { /* to clear float */
content: "";
display: table;
clear: both;
}
}
If you want to use an image in the div that covers the box add also this:
.divImage {
position: relative;
img {
position:absolute;
width: 100%;//might not be necessary, just check if it works without
height: 100%;//might not be necessary, just check if it works without
object-fit:cover; //or contain if you dont want it to fill the container
}
}
Using JavaScript, you will need to adjust the ratio on a per image basis and when the page resizes.
let ratio = 1.4;
const width = containerWidth.getBoundingClientRect().width;
const imageHeight = `${width * ratio}px`;

Resize <img> to fit available screen space in smallest dimension with pure CSS [duplicate]

I have made a div (div1), which is equal to the browser window size. Then I have made another div (div2) inside the parent div (div1). Then I have placed an image inside the second div (div2). My browser window size is 1360X638 and my image size is 1600*1200.
I want the image to fit itself according to the parent div's (div1) size. So the image (which is larger than the window size) have to fit itself to the second div (div2), which is equal to window size), and this image will fit exactly to the div's size (so, there isn't any scrolling or cropping of image in the display).
I have searched for some time. The solution I found is to set the maximum height and width to 100%. I did this.
I wrote this part:
<div style="max-width: 100%; max-height: 100%; background-color: red; margin-right: 0px; padding: 2 2 2 2; overflow:visible;">
<div style="max-height: 100%; max-width: 100%;">
<img style="max-width: 100%; max-height: 100%; overflow:visible;" src="1.jpg" />
</div>
</div>
The output is like this:
You can see there is a scroll in the right side. I don't want that there.
jQuery Solution - Proof of Concept
Suppose you have the following HTML:
<div class="container">
<img src="http://placehold.it/1600x1200" />
</div>
You can apply the following CSS rules to size an image to fit the view port (100% of browser width or height):
html, body {
height: 100%;
margin: 0;
}
.container {
height: 100%;
width: 100%;
background-color: red;
text-align: center; /* optional */
}
.container img {
vertical-align: top;
}
.portrait img {
width: 100%;
}
.landscape img {
height: 100%;
}
Use the following jQuery method to pick the correct CSS rule depending on the aspect ratio of the view port:
function resizeImg() {
var thisImg= $('.container');
var refH = thisImg.height();
var refW = thisImg.width();
var refRatio = refW/refH;
var imgH = thisImg.children("img").height();
var imgW = thisImg.children("img").width();
if ( (imgW/imgH) > refRatio ) {
thisImg.addClass("portrait");
thisImg.removeClass("landscape");
} else {
thisImg.addClass("landscape");
thisImg.removeClass("portrait");
}
}
$(document).ready(resizeImg())
$(window).resize(function(){
resizeImg();
});
Demo fiddle: http://jsfiddle.net/audetwebdesign/y2L3Q/
This may not be the entire answer but it may be a place to start.
Reference
I worked on a related problem earlier, which may be of interest:
Make image fill div completely without stretching

How to always center a flexible square in viewport with pure CSS?

I know this question: Height equal to dynamic width (CSS fluid layout)
But I want more!! I want a flexible container which has always the aspect ratio of a square but with max-height and max-width of 100% of the page (the window element) and on the top of it is always vertically and horizontally centered.
Like this:
// Container matches height of the window
// container-height = 100%; container-width = absolute-container-height
-page/browser-window-
- ####### -
- #cont-# -
- #ainer# -
- ####### -
---------------------
// container matches width of the window
// container-width = 100%; container-height = absolute-container-width
--page---
- -
- -
-#######-
-#######-
-#######-
-#######-
- -
- -
---------
Is it possible to achieve this with pure css (and even better cross-browser)?
Edit:
I know there is calc() for css3, but due to the poor mobile browser-support, I don't want to use it.
Edit2:
Seems like, I didn't make myself clear enough. I need height and width of the wrapper to match the height OR the width of the window, depending on which is smaller.The square-container should never exceed the smaller value of the window-height/width.
This is, how it would be done with jQuery:
// container/#main-wrapper has top: 50%, left: 50%, position: absolute via css
$(window).resize(function () {
var $ww = $(window).width();
var $wh = $(window).height();
if ($ww > $wh) {
$('#main-wrapper').css({
height: $wh,
width: $wh,
marginTop : ($wh / 2) * -1,
marginLeft : ($wh / 2) * -1
});
} else {
$('#main-wrapper').css({
height: $ww,
width: $ww,
marginTop : ($ww / 2) * -1,
marginLeft : ($ww / 2) * -1
});
}
});
I finally figured it out. The magic ingredients are the view-port units.
Given this html structure:
.l-table
.l-table-cell
.square
You can use this css (well actuall its scss, but you get the idea) to make it work
html,
body{
height: 100%
}
l-table{
background: orange;
display: table;
height: 100%;
width: 100%;
}
.l-table-cell{
display: table-cell;
vertical-align: middle;
border: 2px solid black;
}
.square{
background: red;
margin: auto;
#media (orientation:landscape) {
width: 70vh;
height: 70vh;
}
#media screen and (orientation:portrait) {
width: 70vw;
height: 70vw;
}
}
http://codepen.io/johannesjo/pen/rvFxJ
For those who need it, there is a polyfill.
EDIT: Since writing the below, I appealed on Twitter and got a response from Brian Johnson. He came up with a solution that isn't 100% perfect semantically, but it's pretty damn good and I'll certainly be using it. He asked that I share it in this discussion. LINK
I'm having the same issue right now and I was just typing out pretty much this exact question, so although I can't answer it, I wanted to share what I've found so far in case it helps anyone come up with the final solution.
To clarify, I need my content to fit into a square which fills 60% of the browser's width if portrait or 60% of the height if landscape.
However, this square must never exceed the width or height of the viewport.
Using the technique found here I've managed to create the fluid square, but it still exceeds the viewport when landscape.
width: 60%;
height:0;
padding-bottom: 60%;
Link to Codepen example
I have tried flipping that technique on it's side for landscape but that doesn't work. (You can see that code in the above example, noted out.)
I can't use a simple max-height property because the height is being worked out by the padding-bottom property.
I've thought about adding an extra div as someone else has suggested (C-Link's post is really interesting) but I can't work out how I'd get it to do what we want it do here.
html
<div id="outer">
<div id="inner">YOUR CONTENTS HERE
</div>
</div>
css
html, body{
height: 100%;
}
#outer{
max-height: 100%;
max-width: 100%;
position: relative;
height: 100%;
}
#inner{
position: relative;
top: 50%;
margin-top: -50% auto auto auto;
background: red;
text-align: center;
color: yellow;
}
See this fiddle.
How about if you take the earlier concept a step further with a similar div as a container. The container has an added max-height & width. I tried this and the container does not throw a scrollbar at me. It is quite interesting in behavior I must say myself. Does this work for you?
<div id="container">
<div id="centered">A DIV</div>
</div>
#container {
top:0;
bottom:0;
right:0;
left:0;
margin:auto;
position:absolute;
width:200px;
height:200px;
max-width:100%;
max-height:100%;
background:#00f;
padding:0;
}
#centered {
background: green;
bottom: 0;
height: 80px;
left: 0;
margin: auto;
position: absolute;
top: 0;
right: 0;
width: 80px;
}
updated fiddle:
http://jsfiddle.net/djwave28/mBBJM/96/

Resources