Calculate aspect ratio of an image to get equal heights with flexbox - html

I was taking a look at:
this code pen about equal responsive height images
I want images to have the same height, despite their width/height differences.
As can be seen in the CSS below, there is usage of flexbox with flex to get the images as this:
/* Important stuff for this demo. */
img {
width: 100%;
height: auto;
vertical-align: middle;
}
.pics_in_a_row {
display: flex;
}
.img1 { flex: 1.3344; } /* <-- how can I calculate this part? */
.img2 { flex: 1.3345; }
.img3 { flex: 0.7505; }
.img4 { flex: 1.5023; }
.img5 { flex: 0.75; }
How can I calculate the part of the flex : number. I guess this is the aspect ratio?

The aspect ratio is X/Y of the image size.
So if the image is 600 pixels wide and 800 pixels high, the aspect ratio would be 600/800=0.75
When knowing this, you can choose one of the methods proposed in the article you referenced:
With the CSS methods, you do have a few options for specifying the
aspect ratio:
Work out the aspect ratio yourself and hard-code it into the CSS (as done in this demo)
Use CSS's calc() to calculate the aspect ratio (e.g. flex: calc(600/800);)
Use a preprocessor to calculate the aspect ratio at build time

I was struggling with this myself. You get the image ratio by dividing its width and height. If you don't use JavaScript just open your calculator and divide image width with the height. If you use JavaScript then to get the flex value you need to divide image width/height. Like this:
const imageRatio = img.naturalWidth / img.naturalHeight;
When getting the value you can use naturalWidth and naturalHeight values that return the original size of the image. I used only height and width in the beginning but it is from the browser and might return incorrect values in some cases (loading image etc).
https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth
What I ended up doing is that I calculate the column widths with JavaScript instead of the flex because it doesn't work if there is text inside the column. Then the math becomes more complex. You have to get the ratio of all images, sum them and you get the total ratio. Then you divide the image ratio with this full ratio to get the percentage.
Here is some pseudocode:
const getFullRatio = (images) => images.reduce((acc, curr) => (curr.naturalWidth / curr.naturalHeight) + acc, 0);
const containerWidth = 740;
const columnAmount = images.length;
const columnMargin = 15;
const marginPercentageToAdd = ((columnAmount * columnMargin) / containerWidth) + 1;
const fullRatio = getFullRatio(images);
const fullRatioWithMargins = fullRatio * marginPercentageToAdd;
images.forEach((img) => {
const imageRatio = img.naturalWidth / img.naturalHeight;
const columnRatio = (imageRatio / fullRatioWithMargins) * 100;
const imageParentDiv = img.closest('.COLUMNCLASS');
imageParentDiv.style.width = `${columnRatio}%`;
const image = img;
image.style.width = '100%';
});

Related

Fit (contain) <img> of unknown size to parent, keeping aspect ratio WITHOUT img-element having same w/h as parent [duplicate]

I realise this has been asked many times under many guises, but most solutions seem to not care about the resulting image height, or only scale in one direction. This:
min-width: 100%;
height: auto;
isn't a solution.
I'm trying to fit an image to the height and width so that it can be dynamically injected into a number of places in different systems and sites, so I don't necessarily know what the parent object is going to be - might be a div with or without overflow set, or a p, or the body - or its dimensions; The parent container mustn't change size just by injecting my image/script .. jQuery is NOT available.
I can't see how the css3 background technique would work.
Proportional scaling is as easy as using a ratio:
<img onload="scale(this)" src="screenshot.png">
<script type="text/javascript">
function scale(img){
var p = img.parentNode,
x = p.offsetWidth,
y = p.offsetHeight,
w = img.naturalWidth,
h = img.naturalHeight;
ratio = h / w;
if (h >= y) {
h = y;
w = h / ratio;
img.style.width = w + "px";
img.style.height = h + "px";
} else if(w >= x) { //} && ratio <= 1){
w = x;
h = w * ratio;
img.style.width = w + "px";
img.style.height = h + "px";
}
}
</script>
but this only scales in one plane - I need it to continue to scale both width and height until it fits into the parent container space neatly in both dimensions. If the image is smaller than the parent container, it should scale UP to fill proportionally.
Adapt image to fit parent container (of unknown size) without stretching image
Instead of messing with JS, let CSS do the job!
Set your image to 100%; height and width;
Replace your image's src with a transparent pixel and set it's background to the actual src.
Use CSS's background-size on your (now) full-sized image:
contain (image will cover the parent completely)
cover (image will respect image proportions instead)
Example using contain
function scale( img ) {
if(img.isScaled) return;
img.style.background="no-repeat url("+ img.src +") 50%";
img.style.backgroundSize="contain"; // Use "contain", "cover" or a % value
img.style.width="100%";
img.style.height="100%";
img.isScaled=true; // Prevent triggering another onload on src change
img.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
}
<div style="width:300px; height:300px; background:#000; margin:10px;">
<img onload="scale(this);" src="//placehold.it/1200x600/f0f">
</div>
<div style="width:300px; height:300px; background:#000; margin:10px;">
<img onload="scale(this);" src="//placehold.it/400x600/cf5">
</div>
Tested in: FF, CH, E, IE(11), SA
NB: The transparent pixel data is used solely to prevent the browser's Missing Iimage Icon that would be otherwise caused by doing img.src = "";
http://caniuse.com/#search=background-size
I used this code to fit a video to its parent:
var parent = vid.parentNode,
vw = vid.videoWidth,
vh = vid.videoHeight,
vr = vh / vw, // video ratio
pw = parent.offsetWidth,
ph = parent.offsetHeight,
pr = ph / pw; // parent ratio
if(pr > vr) {
vid.style.width = 'unset';
vid.style.height = `${ph}px`;
} else {
vid.style.height = 'unset';
vid.style.width = `${pw}px`;
}

How to fetch aspect ratio within HTML and CSS?

Responsive website depends on #media queries which takes value in terms of pixels or screen type.
Is there a way to set media query using aspect ratio of the screen that is being used? How?
Also how to fetch or calculate the aspect ratio of the current screen on which the web page is being displayed from HTML and CSS?
Sadly there's no such thing in CSS like sw or sh to get the screen width / height.
JS to the rescue!
Use JS's screen.width and screen.height
Use CSS aspect-ratio property
Calculate the aspect-ratio: sw/sh : 1
const set_AR = (el) => el.style.aspectRatio = screen.width / screen.height;
set_AR(document.querySelector("#emulator"));
#emulator {
--scale: 0.6;
max-width: calc(100vw * var(--scale));
max-height: calc(100vh * var(--scale));
background: #000;
}
<div id="emulator"></div>

CSS - Position elements on the same place despite of device's screen size

I am developing an Ionic App and it needs to have some buttons (one above another, not inline) on the bottom-left place of the device's screen
I have the following CSS:
.button {
left = "1em";
z-index = "13";
overflow = "scroll";
position = "absolute";
width = "3em";
height = "2.5em";
textAlign = "center";
}
and then I calculate its bottom like this:
let bottom: number = 0;
this.floors.forEach(floor => {
let floorButton: HTMLElement = document.createElement("button");
floorButton.setAttribute("class", "button");
floorButton.appendChild(document.createTextNode(floor.level));
floorButton.style.bottom = bottom + "em";
bottom = bottom + 5;
});
Now my problem is simple: in a device with a bigger screen than another device, it is positioning in an upper position.
I can workarround this by calculating the height of the device's screen and dividing it x times until I get to the position I want. But this looks dirty to me (I don't know if it's the right wait tho, maybe it is).
So my question is, is there a simpler way that doing this as the one I put above instead of having to calculate the screen's height size in pixels? Can it be done directly by CSS? I've checked #media but it looks like it won't help at all. Or maybe I'm just doing it right and I'm overthinking it too much?
Thanks!
You can just use CSS for this:
.button {
display: block;
margin-top: 5px;
}
In this way doesn't matter what is the width of screen, always your buttons will be in separate line.

How to maintain position and size for all window sizes in CSS?

I want the image to be at the center of the window, and of the same size irrespective of the window size. Im not sure on how to do this, any kind of help will be appreciated.
Or you can use JavaScript to do it
In case the piscture is 600px x 400px:
var w = ((window.innerWidth)-600)/2;
var h = ((window.innerHeight)-400)/2;
var img = document.getELementByTagName('IMG')[0];
img.style.marginLeft = w+'px';
img.style.marginTop = h+'px';
You must just add the concrete size of the picture in CSS, like this:
img {
width: 600px;
height: 400px;
}
The image will be 600px x 400px in all screen resolutions.

How to get Aspect Ratio of device in Cocos2d-x?

Is there any way to get the aspect ratio of device. For example whether it is 16:9 or 4:3 or 3:2?
I want to exact fit resources for these resolutions. The problem i face is device dont give the exact values for example width/ height of iPhone 4inch is not exactly 16:9 but relatively equal. Is there any way to get the devices aspect ratio?
thanks in advance
This is pseudo code to get aspect-ratio of the screen. You might need to set table has 16:9, 4:3, 3:2, or whatever you want aspect-ratio entries.
auto frameSize = Director::getInstance()->getOpenGLView()->getFrameSize();
auto aspectRatio = frameSize.width / frameSize.height;
int aspectRatioType = DEFAULT_ASPECT_RATIO_TYPE;
float closest = FLT_MAX;
for (const auto& i : table) {
auto d = fabs(i.aspectRatio - aspectRatio);
if (d < closest) {
closest = d;
aspectRatioType = i.aspectRatioType;
}
}
return aspectRatioType;