How can I scale all images to the same dimensional area? [closed] - css

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 10 months ago.
Improve this question
I'm loading in several images. They are various lengths and widths, but I would like for them all to feel as though they are the same "size". So, if one image is 200x100 and another image is 200x400, I would like for them both to scale in such a way that they take up the same amount of space on the screen. If I fix the width to be 200, then the second element is 4 times the size of the first.
For example:
.my_img {
width: 200px;
}
produces this behavior
How can I use css to fix the area of an image or other element? Where by area, I mean literally length times width. I would like to load in an image of arbitrary dimensions, and scale it (preserving aspect ratio) so that its area is fixed to be a given value.

I don't believe you can do this with CSS. While you can calculate square root with CSS in various ways, getting natural dimensions may be problematic. You'd need that in order to find the smallest image.
For a JavaScript solution, you'd have to first establish the smallest image area, then resize each down according to initial proportion, maintaining aspect ratio.
const images = document.querySelectorAll('img');
let smallestArea = 999999999;
const getSmallestImageByArea = () => {
images.forEach(image => {
const width = image.naturalWidth;
const height = image.naturalHeight;
if (width * height < smallestArea) {
smallestArea = width * height;
}
});
};
const sizeImagesToSmallestArea = () => {
images.forEach(image => {
let width = image.naturalWidth;
let height = image.naturalHeight;
const area = width * height;
if (area > smallestArea) {
const areaRoot = Math.sqrt(area);
const proportion = areaRoot / Math.sqrt(smallestArea);
const aspectRoot = Math.sqrt(width / height);
width = areaRoot / proportion * aspectRoot;
height = areaRoot / proportion / aspectRoot;
image.style.width = width + 'px';
image.style.height = height + 'px';
}
// show hidden images
image.style.display = 'inline';
console.log('Initial area:', area, '| Final area:', width * height);
});
};
// wait for images: https://stackoverflow.com/a/60949881/1264804
Promise.all(Array.from(document.images)
.filter(img => !img.complete)
.map(img => new Promise(resolve => {
img.onload = img.onerror = resolve;
}))).then(() => {
getSmallestImageByArea();
sizeImagesToSmallestArea();
});
/* hide images to prevent jumping effect */
img {
display: none;
}
<img src="https://via.placeholder.com/165x250" />
<img src="https://via.placeholder.com/100x50" />
<img src="https://via.placeholder.com/200x200" />
<img src="https://via.placeholder.com/1900x300" />

Maybe you can try something like this. if you want them to fit on a specific container you have to wrap them and set their height and width and let them fit on it using obejct-fit:cover. This sample have 2 different size images but they fit exactly the way I would do it no matter how big they are. Let me know if this is what you are looking at??
.my_img {
justify-content:space-around;
display:flex;
}
.my_img > img {
object-fit: fill;
height: 300px;
width: 300px;
border: 1px solid gray;
margin: 10px;
overflow:visible;
}
<div class="my_img">
<img src="https://www.kindpng.com/picc/m/227-2275045_daisy-yellow-bloom-frame-flower-border-flowers-transparent.png">
<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.clir.org%2Fwp-content%2Fuploads%2Fsites%2F6%2F2016%2F09%2FWelcome-banner.png&f=1&nofb=1">
</div>

Related

How to center items inside konvajs?

I am currently building some sort of meme-editor in react and for that I am using konvajs to function similar to a Canvas.
My problem is that I am unable to center the items inside the canva stage, as there seems to be some property that just overrides my styling.
This is (part of) the return statement in my react-component:
<div className="mycanvas">
<Stage width={500} height={500} className="stage">
<Layer>
<Image image={image} className="meme" />
{textFields.map((text) => (
<Text
text={text}
draggable
fontFamily="Impact"
fontSize="30"
stroke="white"
/>
))}
</Layer>
</Stage>
</div>
And this is how the output gets rendered.
I have coloured the background of the wrapper blue, to show in which box the image should be centered.
I have already tried CSS on the classes "mycanvas", "stage" and "meme" and also on "konvajs-content" (as that showed up in my inspector for some reason). I have used align-items: center, margin: auto and a couple others, but I think normal CSS does not really apply here.
I think it is an issue regarding the generaly styling of konvajs components, but unfortunately I could not find any solution on stackoverflow or the konva documentation.
This is an instance where CSS can't help. When the image is applied to the canvas using its height and width at the x and y coordinates you supply, the pixels of the image become part of the rasterized canvas. In other words, the image doesn't exist independent of the canvas.
Therefore, if you want to center the image inside of your canvas, you need to do a little math to calculate the x and y coordinates that will place the image centered inside the canvas.
Demo
For example, if your canvas size is 500px tall and your image has a height of 350px, then you need to set the y position to 75px (i.e., (500 - 350) / 2).
The demo code below shows how to replicate the behavior of CSS object-fit: contain. This will adjust the image to fill the canvas in one direction, and then center the image in the other direction.
import { useState, useEffect } from "react";
import { Stage, Layer, Image, Text } from "react-konva";
function Example() {
const w = window.innerWidth;
const h = window.innerHeight;
const src = "https://konvajs.org/assets/yoda.jpg";
const [image, setImage] = useState(null);
const [pos, setPos] = useState({ x: 0, y: 0 });
useEffect(() => {
const image = new window.Image();
image.src = src;
image.addEventListener("load", handleLoad);
function handleLoad(event) {
const image = event.currentTarget;
/* after the image is loaded, you can get it's dimensions */
const imgNaturalWidth = image.width;
const imgNaturalHeight = image.height;
/*
calculate the horizontal and vertical ratio of the
image dimensions versus the canvas dimensions
*/
const hRatio = w / imgNaturalWidth;
const vRatio = h / imgNaturalHeight;
/*
to replicate the CSS Object-Fit "contain" behavior,
choose the smaller of the horizontal and vertical
ratios
if you want a "cover" behavior, use Math.max to
choose the larger of the two ratios instead
*/
const ratio = Math.min(hRatio, vRatio);
/*
scale the image to fit the canvas
*/
image.width = imgNaturalWidth * ratio;
image.height = imgNaturalHeight * ratio;
/*
calculate the offsets so the image is centered inside
the canvas
*/
const xOffset = (w - image.width) / 2;
const yOffset = (h - image.height) / 2;
setPos({
x: xOffset,
y: yOffset
});
setImage(image);
}
return () => {
image.removeEventListener("load", handleLoad);
};
}, [src, h, w]);
return (
<Stage width={w} height={h} style={{ background: "black" }}>
<Layer>
<Image x={pos.x} y={pos.y} image={image} />
<Text
text="I am centered"
fontFamily="Impact"
fontSize={50}
stroke="white"
strokeWidth={1}
x={pos.x}
y={pos.y}
/>
</Layer>
</Stage>
);
}

How does a child scale font-size contingent on the parent? [duplicate]

This question already has answers here:
Font scaling based on size of container
(41 answers)
Closed 1 year ago.
I have a container that has a % width and height, so it scales depending on external factors. I would like the font inside the container to be a constant size relative to the size of containers. Is there any good way to do this using CSS? The font-size: x% would only scale the font according to the original font size (which would be 100%).
If you want to set the font-size as a percentage of the viewport width, use the vwunit:
#mydiv { font-size: 5vw; }
The other alternative is to use SVG embedded in the HTML. It will just be a few lines. The font-size attribute to the text element will be interpreted as "user units", for instance those the viewport is defined in terms of. So if you define viewport as 0 0 100 100, then a font-size of 1 will be one one-hundredth of the size of the svg element.
And no, there is no way to do this in CSS using calculations. The problem is that percentages used for font-size, including percentages inside a calculation, are interpreted in terms of the inherited font size, not the size of the container. CSS could use a unit called bw (box-width) for this purpose, so you could say div { font-size: 5bw; }, but I've never heard this proposed.
Another js alternative:
Working Example
fontsize = function () {
var fontSize = $("#container").width() * 0.10; // 10% of container width
$("#container h1").css('font-size', fontSize);
};
$(window).resize(fontsize);
$(document).ready(fontsize);
Or as stated in torazaburo's answer you could use svg. I put together a simple example as a proof of concept:
SVG Example
<div id="container">
<svg width="100%" height="100%" viewBox="0 0 13 15">
<text x="0" y="13">X</text>
</svg>
</div>
You may be able to do this with CSS3 using calculations, however it would most likely be safer to use JavaScript.
Here is an example: http://jsfiddle.net/8TrTU/
Using JS you can change the height of the text, then simply bind this same calculation to a resize event, during resize so it scales while the user is making adjustments, or however you are allowing resizing of your elements.
I used Fittext on some of my projects and it looks like a good solution to a problem like this.
FitText makes font-sizes flexible. Use this plugin on your fluid or responsive layout to achieve scalable headlines that fill the width of a parent element.
It cannot be accomplished with css font-size
Assuming that "external factors" you are referring to could be picked up by media queries, you could use them - adjustments will likely have to be limited to a set of predefined sizes.
Here is the function:
document.body.setScaledFont = function(f) {
var s = this.offsetWidth, fs = s * f;
this.style.fontSize = fs + '%';
return this
};
Then convert all your documents child element font sizes to em's or %.
Then add something like this to your code to set the base font size.
document.body.setScaledFont(0.35);
window.onresize = function() {
document.body.setScaledFont(0.35);
}
http://jsfiddle.net/0tpvccjt/
I had a similar issue but I had to consider other issues that #apaul34208 example did not tackle. In my case;
I have a container that changed size depending on the viewport using media queries
Text inside is dynamically generated
I want to scale up as well as down
Not the most elegant of examples but it does the trick for me. Consider using throttling the window resize (https://lodash.com/)
var TextFit = function(){
var container = $('.container');
container.each(function(){
var container_width = $(this).width(),
width_offset = parseInt($(this).data('width-offset')),
font_container = $(this).find('.font-container');
if ( width_offset > 0 ) {
container_width -= width_offset;
}
font_container.each(function(){
var font_container_width = $(this).width(),
font_size = parseFloat( $(this).css('font-size') );
var diff = Math.max(container_width, font_container_width) - Math.min(container_width, font_container_width);
var diff_percentage = Math.round( ( diff / Math.max(container_width, font_container_width) ) * 100 );
if (diff_percentage !== 0){
if ( container_width > font_container_width ) {
new_font_size = font_size + Math.round( ( font_size / 100 ) * diff_percentage );
} else if ( container_width < font_container_width ) {
new_font_size = font_size - Math.round( ( font_size / 100 ) * diff_percentage );
}
}
$(this).css('font-size', new_font_size + 'px');
});
});
}
$(function(){
TextFit();
$(window).resize(function(){
TextFit();
});
});
.container {
width:341px;
height:341px;
background-color:#000;
padding:20px;
}
.font-container {
font-size:131px;
text-align:center;
color:#fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container" data-width-offset="10">
<span class="font-container">£5000</span>
</div>
https://jsfiddle.net/Merch80/b8hoctfb/7/
I've given a more detailed answer of using vw with respect to specific container sizing in this answer, so I won't just repeat my answer here.
In summary, however, it is essentially a matter of factoring (or controlling) what the container size is going to be with respect to viewport, and then working out the proper vw sizing based on that for the container, taking mind of what needs to happen if something is dynamically resized.
So if you wanted a 5vw size at a container at 100% of the viewport width, then one at 75% of the viewport width you would probably want to be (5vw * .75) = 3.75vw.
If you want to scale it depending on the element width, you can use this web component:
https://github.com/pomber/full-width-text
Check the demo here:
https://pomber.github.io/full-width-text/
The usage is like this:
<full-width-text>Lorem Ipsum</full-width-text>
You can also try this pure CSS method:
font-size: calc(100% - 0.3em);

CSS: Make Canvas as big as possible while keeping aspect ratio

I have a Canvas element that is inside a container div. When the user selects an image from his machine, this image should be displayed on the canvas. I want the canvas to be big as possible but at the same time keep the aspect ratio of the image. I know neither the proportions of the image nor the size of the container div, as this is relative to the screen/window size of the user.
If I set max-width and max-height to e.g 100% the canvas will not fill the container if the selected image is smaller then the container. If I set width and height instead of max-width and max-height the canvas doesn't keep the aspect ratio.
Does anyone have an idea how to solve this?
If you're willing to use JQuery (or regular JavaScript), then a solution like this might work:
<script>
// Note: this uses jQuery.
// It makes getting/setting the dimensions easier,
// but you can do this with normal JavaScript
var img = $("#img");
var container = $("#container");
var width = img.width();
var height = img.height();
var maxWidth = container.width();
var maxHeight = container.height();
var ratio = maxWidth / width;
if(height * ratio > maxHeight) {
ratio = maxHeight / height;
}
img.width(width * ratio);
img.height(height * ratio);
</script>
What this does is that it finds the ratio to multiply the width and the height by, whichever one is smaller (so that it will always fit in the window).
Update: Tested on JSFiddle.net. See it here.
I hope this helps you!
After reading your clarification about video, check out the following:
https://jsfiddle.net/d0dox9xt/
body {
background: #eee;
}
#container {
margin:0 2% 0 2%;
}
#v {
position:absolute;
top:0;
left:0;
width:100%;
}
The only trick is setting width:100%; This will maintain aspect ratio.
Note that in the JS
document.addEventListener('DOMContentLoaded', function(){
var v = document.getElementById('v');
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
}
function draw(v) {
c.drawImage(v, 0, 0);
}
The drawImage function can take many arguments. The first argument is inserting the media, the next two are for positioning. There are many arguments you can have to position and change the height and width. I left them alone so it will follow the CSS rules.
Here is a link to more on placing in canvas: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

Many floating DIVs same height [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have such situation: http://jsfiddle.net/HKHS3/
The question is how to make divs appear row after row where all divs in one row have the same height, depending on actual content of the tallest one?
So, depending on body's width the number of divs in a row will vary but each time the div right after the end of row should kind of clear floating and start a new row.
Fixed number per row
You can do this by creating a row type div to wrap your inner div elements.
First you need to restructure your HTML, something like this:
<div class="row">
<div>abc</div>
<div>adb djhf kdfhv fkjsh vhf jhds fjhf jh fjhf jh fdjh dh</div>
<div>dhfjgh jfh gkjhfde jghf jgh jfdh gjfhd gjfdhg jfhd gjdhf jhg djhg jdh gjhfd</div>
</div>
(you can add more rows like this as you need to)
Then the following css should do what you need:
.row {
display:table-row;
}
.row > div {
width: 100px;
display:inline-block;
vertical-align:top;
border: 1px solid black;
margin: 5px;
height:100%;
}
Here is your example updated
Dynamic number per row (not perfect)
The problem with the above method is that it requires you to have a fixed number of div elements per row. If you wanted it to be dynamic and wrap then you will have a problem doing this with just CSS alone. The closest you could get to it would be as follows:
div {
width: 100px;
display:inline-block;
vertical-align:top;
margin: 5px;
}
But the elements do not all have the same height, it is just you cannot tell that without the border. Due to this, adding a border, background-color or any other style that shows the element's height will break the effect.
Here is an example of this
Exactly as required (requires javascript)
It is worth mentioning that the effect you want is doable using javascript. I wont include an example of this because the actually implementation will depend heavily on how your real HTML is set up.
Actually, I had a quick go at the javascript approach, it uses JQuery though, and can likely be optimised too:
function updateHeights() {
var maxHeight = 0, lastY = 0, rowDivs = [], allDivs = $("div"), count = allDivs.length;
allDivs.each(function (i) {
var div = $(this), offset = div.offset(), y = offset.top, x = offset.left, h = div.height();
if (h > maxHeight) maxHeight = h;//store the highest value for this row so far
if (lastY == 0) lastY = y;//get the y position if this is the first element
//if new row
if (y > lastY) {
resizeElements(rowDivs, maxHeight);//resize all elements on this row
rowDivs.length = 0;//reset the array of row elements, ready for next row
maxHeight = h;//set maxHeight to first of new row
}
lastY = y;//store current y posible for checking if we have a new row or not
rowDivs.push(div);//add current element to row collection
//check if last item, is so then resize this last row
if(count - 1 == i)
resizeElements(rowDivs, maxHeight);
});
}
function resizeElements(elements, height) {
for (var i = 0; i < elements.length; i++) {
$(elements[i]).height(height);
}
}
$(window).resize(function () {
updateHeights();
});
updateHeights();
Here is a working example
It is very simple using jQuery. For all divs in same row give single class. Lets say 'sameheight' in my example. Then use this jQuery.
$(document).ready(function(){
var maxHeight = 0;
$(".sameheight").each(function(){
if ($(this).height() > maxHeight) { maxHeight = $(this).height(); }
});
$(".sameheight").height(maxHeight);
});
For multiple rows repeat the code with different class.
Hope this solves your issue.
try this
<script type="text/javascript">
$(document).ready(function () {
var maxHeight = 0;
$('div').each(function () {
var this_div = $(this);
if (maxHeight < this_div.height()) {
maxHeight = this_div.height();
}
})
$('div').css({ 'height': maxHeight.toString() });
})
</script>

HTML & CSS How to prevent a div from extending greater the height of the window?

How can I prevent a div which contains a long list of items from expanding the page height. I want the div to take up the entire screen but no more so that it doesn't push the footer down.
Set an specific height for the div container, and also set overflow-y with auto in order to show the scroll bar only when the content of the div is larger than the height set in the container. Like this:
.container {
height: 500px;
overflow-y:auto;
}
Without js, it is not possible because your page can be viewed in different resolution. Different resolutions means different height. Matter of fact, you may want that behaviour when user resizes the browser window as well, am I right? So first, find out the height of the browser, subtract the height of the footer from it, and set this height to your container, which I believe you want to make scroll able on yaxis. That will solve the problem. All these tasks are pretty simple and you can do it by little googling.
Use JavaScript/jQuery for this:
jQuery Solution:
<div id="content-div">some content here</div>
$(document).ready(function() {
var height = $(document).height();
height = height - (your footer height);
$("#content-div").css({ 'max-height' : height.toString() });
});
Standard JavaScript solution:
<div id="content-div">some content here</div>
function myfunction () {
document.getElementById('content-div').style.height = getDocHeight() + 'px';
}
window.onload = myfunction();
document.getElementById('content-div').style.height = getDocHeight() + 'px';
function getDocHeight() {
var D = document;
return Math.max(
Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
Math.max(D.body.clientHeight, D.documentElement.clientHeight)
);
}
Also, change CSS to:
#content-div { background-color:#1d1d1d; color:#eee; overflow-y: scroll; }

Resources