CSS: Element fixed to viewport height, scaled proportionally, centered - css

I have elements which have a set height of 100% viewport height. Inside of these are a background image which is also fixed to the same height - so the image's top and bottom are always visible, it's centered, and sometimes it's edges get cut off.
What I'm trying to add on top of this is another element which matches the same behavior of the background image (to place other things over the image, but ensure they always line up).
I have a working example using Javascript, but wondering if this same behavior could be replicated with CSS. The pinkish box is the element which I am scaling based on the viewport's size and it should always match up with the background image behind it.
https://jsfiddle.net/louiswalch/p1rkohzt/
And all the scaling logic is as follows:
var $window = $(window);
var base_width = 1600;
var base_height = 960;
var base_ratio = (base_width / base_height);
var contents = $('SECTION .content');
$window.on('resize', function() {
var window_width = $window.width();
var window_height = $window.height();
var window_ratio = (window_height / window_height);
var scaled_width = (window_height * 100/base_height) * base_width/100;
contents.css({
width: (scaled_width+'px'),
height: (window_height+'px'),
marginLeft: ('-'+scaled_width/2+'px'),
});
}).trigger('resize');

Related

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

Delete white spaces on html5 video tag in Ionic

I have a video tag in my Ionic app, video element is added after click on a button.
function addVideo(videoId){
var path = $scope.getVideo(videoId).newVideoLocation.nativeURL;
path = $sce.trustAsResourceUrl(path);
var container = document.getElementById('videoContainer' + videoId);
var video = document.createElement('video');
video.src = path;
video.setAttribute('id', 'video' + videoId);
video.setAttribute('poster', $scope.getVideo(videoId).thumbnailPath);
video.setAttribute('width', '100%');
container.appendChild(video);
};
Video is added successfully but there are bottom and top white spaces / bars:
After click play button spaces are no longer there:
I set border to all elements to know what is happening. Blue border is video tag:
It could be margin o padding however I set them to 0:
* {
border: 1px solid red !important;
}
video {
border: 2px solid blue !important;
margin: 0;
padding: 0;
}
Any idea what is the problem?
After a lot of research I found a solution.
I start understanding what happened after read HTML 5 Video stretch post:
Video content should be rendered inside the element's playback area
such that the video content is shown centered in the playback area at
the largest possible size that fits completely within it, with the
video content's aspect ratio being preserved. Thus, if the aspect
ratio of the playback area does not match the aspect ratio of the
video, the video will be shown letterboxed or pillarboxed. Areas of
the element's playback area that do not contain the video represent
nothing.
Then in google books I found and explanation how works video width, the book is call The Definitive Guide to HTML5 Video
If width and height are not same aspect ratio as original video it doesn't work. Set a 100% to width doesn't mean you want video to fit the container. So I decided to calculate width and height of the container and set to video element:
function addVideo(videoId){
var path = getTrustUrl($scope.getVideo(videoId).newVideoLocation.nativeURL);
// Create container element and get padding
var container = document.getElementById('videoContainer' + videoId);
var paddingLeft = window.getComputedStyle(container, null).getPropertyValue('padding-left');
var paddingRight = window.getComputedStyle(container, null).getPropertyValue('padding-right');
// Get only numeric part and parse to integer
paddingLeft = parseInt(paddingLeft.slice(0,-2));
paddingRight = parseInt(paddingRight.slice(0,-2));
//Get internal width of container and calculate height
var width = container.offsetWidth - paddingLeft - paddingRight;
var height = (width * 9 ) / 16; // TODO, if not 16:9 error
// Create video element and set attributes
var video = document.createElement('video');
video.src = path;
video.setAttribute('id', 'video' + videoId);
video.setAttribute('poster', $scope.getVideo(videoId).thumbnailPath);
video.setAttribute('width', width);
video.setAttribute('height', height);
// Append video to container
container.appendChild(video);
};
I don't see it straightforward... if someone know another solution let me know!

HTML5 Canvas fills windows with full resolution

I am trying to achieve a layout like this:
where:
Navbar is just a bootstrap-like top menu, 60px of height, always on top
Pop-up menu is fixed in that position (not always visible), always on top
The entire free area (windows w.o. navbar) is filled with Canvas.
Live example: jsFiddle
I have a problem with Canvas. I currently have a simple style:
<canvas id="le_canvas">Y U NO CANVAS</canvas>
...
#le-canvas {
position:absolute;
width:100%;
height:100%;
}
and the canvas is filling the background, but:
the resolution is very low
it doesn't maintain ratio during window resizes.
What I'd like (if it is possible):
full resolution of the area to fill (1:1 pixel on canvas and on screen)
set the ratio of the area to fill
bonus: update the above after window resize
Setting the canvas element in per-centage will not set the actual canvas size which must be set in absolute pixels. What happens here is that you get a canvas with a default size which then is stretched by the html-rendering giving the blurry look.
You therefor need to set the size by using f.ex. the window's sizes in absolute pixels.
You can do this like this (update of fiddle here: http://jsfiddle.net/x5LpA/3/ ) -
Create a function that sets the canvas size based on window size (you will of course need to subtract height of bars etc, but to show the principle):
function initCanvasArea(cnv) {
cnv.width = window.innerWidth;
cnv.height = window.innerHeight;
}
As the canvas content are cleared when the canvas is re-sized you need to render the content again for each time. Therefor it will be smart to extract the render content into a separate function like f.ex:
function renderCanvas(ctx) {
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(0, 0, 55, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect(20, 20, 55, 50);
}
Now, make the main function a self-invoking one where you also attach an event handler for windo.resize to update the canvas:
$(function () {
var canvas = $('#le_canvas')[0];
var ctx = canvas.getContext('2d');
initCanvasArea(canvas);
renderCanvas(ctx);
window.onresize = function(e) {
initCanvasArea(canvas);
renderCanvas(ctx);
};
})();
And finally edit the CSS-rule by removing the width/height set to 100%;
#le_canvas {
position:absolute;
}
(Tip: a better approach here is to use the fixed attribute for position - plus use a wrapper element, padding, box-sizing.. but that is out of scope for this question).
Is this what you are after? I used $(document).width() and $(document).height() to get the width and height for the rectangle. http://jsfiddle.net/x5LpA/1/

Background-size cover jumping when background-position switches to fixed

I am working on a Parallax/Scrolling Timeline project and I am having a problem with the CSS3 Background-size cover property.
The div has these properties:
background: url(../images/timeline/back-6.jpg) no-repeat top center black;
background-size: cover;
padding-top: 90px;
height: 1855px;
position: relative;
Using jQuery I switch the background-attachment to fixed. When I do this the background image jumps "in" (meaning that parts of the image that were past the edge of the screen are now visible). Which isn't the desired result.
In testing I can switch the div to use background-size: 100% cover but it is causing different vertical jumping issues when scrolling.
Any ideas of how to prevent it from jumping in when I switch the background to fixed? (It also happens in reverse when I set the background to scroll).
I sadly can't link to a demo of this code as the page isn't ready to be deployed yet.
I had the same issue, when setting background-size to cover or contain
Setting a fixed height, in example for smaller screens via #media prevents the background-image from jumping. After my tests I came to the conclusion, that the jumping is due to the orientation of the element after setting background-attachment to fixed
Setting it to fixed, the size is calculated by the size of the viewport, not the element containing the background-image. This is where the jumping comes from and why setting a fixed height or width for the background-size solves this issue.
I had the same problem while creating a one page layout i wanted to use with a scrollTo-Plugin and so on....
The page layout was devided in two parts:
Left side for the background image which should change/scroll with the content on the right side.
So i used to make a kind of jquery Plugin to combine both "background-position: fixed" and "background-size: cover".
you just need to define the element by class/id for aligning the background-images.
dont complain about the code. im relatively new to javascript/jquery. but its working ;)
there it is:
function fixedResize() {
var targetEl = $('element where bg-images are in');
var targetWidth = targetEl.width();
var targetHeight = targetEl.height();
var targetPosX = targetEl.offset().left;
var targetPosY = targetEl.offset().top;
var leftRatio = targetWidth / targetHeight;
//console.log('TargetWidth', targetWidth, 'TargetHeight', targetHeight, 'Offset', targetPosX, targetPosY, 'leftRatio', leftRatio);
targetEl.each(function(){
var imgTarget = $(this);
var url = $(this).css('background-image').replace('url(', '').replace(')', '').replace("'", '').replace('"', '');
var bgImg = $('<img />'); // make background-image as image tag for getting width and height of the image
imgTarget.css('background-attachment','fixed');
bgImg.hide();
bgImg.bind('load', function(){
var imgHeight = $(this).height();
var imgWidth = $(this).width();
var imgRatio = imgWidth / imgHeight;
$(this).remove(); // remove img Tags again
// Calculate resize dimensions
if (imgRatio > leftRatio) {
var currentWidth = imgRatio * targetHeight; // image width after resize
var currentHeight = (currentWidth/imgWidth)*imgHeight;
var setToLeft = ((currentWidth - targetWidth)/2);
var imgPosX = targetPosX - setToLeft;
var imgPosY = (currentHeight - targetPosY - currentHeight/2 - targetHeight/2)* -1;
var resizeImg = 'background-size: auto '+ targetHeight +'px;';
} else if (imgRatio < leftRatio){
var currentWidth = targetWidth;
var currentHeight = (currentWidth/imgWidth)*imgHeight;
var imgPosX = targetPosX;
var imgPosY = (currentHeight - targetPosY - currentHeight/2 - targetHeight/2)* -1;
var resizeImg = 'background-size: '+ targetWidth +'px auto;'; // resize background
}
imgTarget.attr('style','background-attachment: fixed; background-position: '+ imgPosX +'px '+ imgPosY +'px;' + resizeImg);
console.log('imgWidth', imgWidth, 'imgHeight', imgHeight, 'imgRatio', imgRatio, 'currentWidth', currentWidth, 'currentHeight', currentHeight, 'setToLeft', setToLeft);
console.log('imgPos', imgPosX, imgPosY, 'setToLeft', setToLeft, targetPosX);
});
$(this).append(bgImg);
bgImg.attr('src', url);
});
}
fixedResize(); // initiate function
$(window).resize(function() {
fixedResize(); // initiate function for window resize (Fluid behavior)
});
or
jsfiddle.net/rowphant/eXb6e/14/

Resizing Image from a decoded ByteArray

I am trying to display a bytearray as a resized image. The Image is displaying correctly, but the sizing is off. Let me explain.
First I have the image data encoded so I need to decode the image data
// Instantiate decoder
var decoder:Base64Decoder = new Base64Decoder();
// Decode image data
decoded.decode(picture.data);
// Export data as a byteArray
var byteArray:ByteArray = decoder.toByteArray();
// Display image
var img:Image = new Image();
img.load(byteArray);
This works. The image is displayed correctly. However, if I hardcode the image (img) height the resized image is shown correctly, but within a box with the original image's dimensions.
For example, if the original image has a height of 300px and a width of 200px and the img.height property is set to 75; the resized image with height of 75 is shown correctly. But the resized image is shown in the upper left corner of the img container that is still set to a height of 300px and a width of 200px. Why does it do that? And what is the fix?
The best way to illustrate the problem is by placing the image inside a VBox and show the borders of the VBox. From the code block above, if I change the image height and set the image to maintain aspect ratio (which by default is set to true but I add it here for completeness). the problem becomes clear.
// Display image
var img:Image = new Image();
img.height = 75; // Hardcode image height (thumbnail)
img.maintainAspectRatio = true;
img.load(byteArray);
// Encapsulate the image inside a VBox to illustrate the problem
var vb:VBox = new VBox();
vb.setStyle('borderStyle', 'solid');
vb.setStyle('borderColor', 'red');
vb.setStyle('borderThickness', 2);
vb.addChild(img);
I have been working on this problem for days and cannot come up with a solution. Any ideas? What am I missing?
The workaround I used is as follows:
I created an event listener for the img display object. Then after the img has loaded, I manually set the height and width of the image. I know what I want the height (preHeight) to be so that is hardcoded. I then calculate the width and set that as the image width. For some reason I had to use the explicitHeight and explicitWidth properties to finally get the sizing right.
I hope this helps someone.
img.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
private function onCreationComplete(event:FlexEvent) : void
{
img.addEventListener(Event.COMPLETE, onImageLoadComplete);
}
private function onImageLoadComplete(event:Event) : void
{
var image:Image = event.currentTarget as Image;
var preHeight:Number = 0;
var h:uint = Bitmap(image.content).bitmapData.height;
var w:uint = Bitmap(image.content).bitmapData.width;
// Check height
preHeight = h > 170 ? 170 : h;
// Set the width
img.explicitWidth = (preHeight * w)/h;
img.explicitHeight = preHeight;
}

Resources