How to achieve responsive canvas height in IE9 - css

I would like a responsive page which contains canvas elements inside a div. I should be able to simply wrap a canvas element inside another block element, and give that canvas a relative width. Although this method works in Chrome, Firefox, Safari, and Opera, or course IE has to be the fly in the ointment! I'm not even trying versions older then IE9--this simple code example does not work as expected in IE9:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test IE9 Canvas Height</title>
<style>
body {
margin: 0;
padding: 0;
}
#container {
position: relative;
padding-top: 32%;
background-color: #88f;
}
.instruments {
position: absolute;
bottom: 0%;
width: 100%;
padding-bottom: 16%;
background-color: #8f8;
}
#circle {
position: absolute;
left: 42%;
width: 16%;
}
</style>
</head>
<body>
<div id="container">
<div class="instruments">
<canvas id="circle"></canvas>
</div>
</div>
<script>
var canvas = document.getElementById("circle");
var ctx = canvas.getContext("2d");
// Default canvas is 300x150, so make it square
canvas.height = canvas.width;
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
</script>
</body>
</html>
This simple page should render a blue block of height 32% of the body width, and then have another block in green overlapping the bottom 1/2. Inside the inner div is a canvas element which does not explicitly set the height and width--so that it can remain fluid for various window/body widths. The canvas should draw a round red circle, with the height completely contained within its containing div. Works great in every other browser except IE9 (and except IE10 too I think).
Even if I do specify a canvas size,
<canvas id="circle" width="300" height="300"></canvas>
it still doesn't work.
Is there something I am doing wrong, or is there a better method to achieve this goal? I do not want to style or code pixel or point sizes, and would prefer to avoid a javascript IE hack. Thank you

Honestly your tone about IE being bad again makes me not want to help you all that much. Dial it down next time.
Your behavior here is kind of undefined, because canvass nature is to "stretch" their content and there is nothing in your code keeping your canvas square so no reason for it to scale evenly... You can see this for yourself by giving the canvas a background color... the short version is add:
height: 100%
to the canvas' css to make it work the way you want it to... hope this helps -ck
UPDATE:
I read your comment and you don't seem to understand that setting the canvas.width and canvas.height only changes the size of the internal "drawing surface" of the element. When you set the element's style (the default is auto) you are setting the display surface's dimensions. The problem that you are running into is that you are expecting the browser to preserve the canvass internal dimensions when one of it's style dimension members is set to auto and the other is not, like how it works with an img tag. Chrome & Firefox seem to behave this way. IE however is just letting your actual dimension come through, so in your case its as if you set the height to 300px. I'm not sure if there is a "spec correct" approach to this yet, but it seems like all implementations are converging on your preferred behavior.
Anyhow, the solution to your problem is to use an img tag since that tag will behave correctly and just use a data uri to get your canvas image into it:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test IE9 Canvas Height</title>
<style>
body {
margin: 0;
padding: 0;
}
#container {
position: relative;
padding-top: 32%;
background-color: #88f;
}
.instruments {
position: absolute;
bottom: 0%;
width: 100%;
padding-bottom: 16%;
background-color: #8f8;
}
#circle {
position: absolute;
left: 42%;
width: 16%;
}
</style>
</head>
<body>
<div id="container">
<div class="instruments">
<img id="circle" src=""/>
</div>
</div>
<script>
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
// Default canvas is 300x150, so make it square
canvas.height = canvas.width = 300;
ctx.beginPath();
ctx.arc(canvas.width/2, canvas.height/2, canvas.width/2, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
var img = document.getElementById('circle');
img.src = canvas.toDataURL();
</script>
</body>
</html>
That will give you the effect you were looking for without need for any further hacks...
On a side note, your css technique of using padding to "size" an element with a percent is a little fragile (like all % based css techniques). If I were using a % based css layout, I would probably using something like this:
<style>
html, body {
margin: 0;
padding: 0;
height:100%;
}
#container {
height: 33%;
background-color: #88f;
}
.instruments {
height:50%;
background-color: #8f8;
position:relative;
top:50%;
}
#circle {
display:block;
margin:auto;
width:auto;
height:100%;
}
</style>
you can see the full thing (with modified css) in action here: http://jsbin.com/ajoTUZA/2/quiet
I hope that this helps -ck

Related

Internet Explorer incorrectly calculates percentage height for generated content in td

IE11 is calculating the height of a table cell as the height of its content (20px) and not as the height of its background (100px).
Other browsers work as expected.
How can I fix that in IE?
Or: what am I doing wrong?
Or: how can I work around that?
I need this so I can draw a vertical line behind a table cell.
1. Restrictions
Some work-arounds are not possible, due to the details of my particular problem.
1.A. Height is not constant
The height is not constant, it depends on the amount of text on another cell.
So I cannot use a fixed line-height either. If I could, I could also just put that fixed size as ::before's height.
1.B. Cannot use a background-image
I cannot work around that by using a repeating background-image because the line is supposed to not be drawn behind an icon that is centred, so I am drawing it by using generated content (::before and ::after) with height: calc(50% - 20px);.
2. Online sample
Try opening the online sample in IE11, and in Firefox or Chrome.
Note that JavaScript shows the first cell to be 100px tall, and the background fills the 100px. But the generated content is only ~20px tall...
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#borked {
background: yellow;
position: relative;
height: 100%;
}
#borked~* {
height: 100px;
}
#borked::before {
content: "";
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 0, 0, 0.3);
}
</style>
</head>
<body>
<table>
<tr><td id="borked">abc</td><td>def</td></tr>
</table>
</body>
<script type="text/javascript">
"use strict";
var borked = document.getElementById("borked");
var c = document.createElement("td");
c.textContent = "(1st cell seems to be " + borked.clientHeight + "px tall)";
borked.parentElement.appendChild(c);
</script>
</html>
Internet Explorer content height is related to closest element with height set in absolute units, such as pixels.
If you want to use % height, you need to set the height on all parent elements, this will be html, body, table ....
Cause this is not possible for you, use this trick to meets your requirements.
"use strict";
var borked = document.getElementById("borked");
var td = document.createElement("td");
td.textContent = "(1st cell seems to be " + borked.clientHeight + "px tall)";
borked.parentElement.appendChild(td);
#borked {
background: yellow;
position: relative;
height: 100%;
overflow: hidden;
}
#borked~* {
height: 100px;
}
#borked::before {
content: "";
position: absolute;
top: 0;
width: 100%;
margin: -99999em;
padding: 99999em;
background-color: rgba(0, 255, 0, 0.3);
}
<table>
<tr><td id="borked">abc</td><td>def</td></tr>
</table>

<img> max-height doesn't work

I need to display an image (and may be some controls near it) at the center (both horizontally and vertically) of the window, while being shrinked to screen height when happens to be bigger (all the images I have are vertical so I don't care about their width).
The underlying content must be hidden with the background.
Code should work in browsers starting from Internet Explorer 8.
I managed to acheive everything but the latter - shrinking to screen height, which I am having problems with.
Here is how I tried to implement it (put in clauses with a resulting code below):
I put everything in a block with fixed positioning and setting 100% to it's width and height - for it to fill the whole window area. Successful.
I use table to center the image vertically, wherefore I set it's height to 100%. Successful.
Inside of the cell I place an image.
3a. When it's height is less then screen size the image is positioned at the center vertically. Successful.
3b. I set max-height to 100% for the image to make it fit into the screen. Unsucsessful! Image pushes the window apart to it's actual height (except of, surprisingly, IE).
Is it possible to solve the task described and what did I do wrong?
(my code:)
view at jsfiddle
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="photoshow">
<table>
<tr>
<td>
<img src="http://s14.postimg.org/e9kwvq2m9/1031_1.jpg">
</td>
</tr>
</table>
</div>
</body>
</html>
CSS:
.photoshow { /* the containing block */
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: pink; /* hiding the underlying content */
}
.photoshow table {
height: 100%;
margin-left: auto; margin-right: auto; /* to center horizontally */
}
.photoshow td {
height: 100%;
vertical-align: middle;
background: yellow; /* just for visual indication */
}
.photoshow img {
max-height: 100%;
}
DEMO
.photoshow .big {
position:fixed;
top:0;
bottom:0;
left:0;
right:0;
margin:auto;
height:100%;
max-height:300px;
}

Centering a position:fixed div

I have been trying for days to center a position:fixed element, a lot of solutions all around the web have been found and yet, either due to inefficiency or my own inexperience, none of them worked.
The scenario is as follows; I want to make an image visor, whenever you click a image a fixed div is made visible, holding said image, this is actually done via JavaScript.
The problem occurs when I want to center the div, no matter which resolution you are using.
#galleryimage{
position:fixed;
z-index:200;
display:none;
max-height: 100%;
max-width: 100%;
}
#galleryimage img{
max-width:100%;
max-height:100%;
}
The images' width and height are unknown variables, I am not experienced enough with JS to handle it, so I wanted to do it with pure CSS. However, I never could get it centered.
Margin just won't work, and the formula with negative margin won't either, as I do not know the width and height variables of these images.
Any solution?
I would use JavaScript + jQuery for this, to make life easier. Here's a good starting point for you:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<style>
#galleryimage{
position:fixed;
z-index:200;
height: 100%;
width: 100%;
opacity: 0;
}
#galleryimage img{
position: absolute;
left: 50%;
top: 50%;
}
</style>
<body>
<div id="galleryimage">
<img src="" />
</div>
</body>
<script type="text/javascript">
$(document).ready(function(){
loadGalleryImage('your_image_name.jpg');
});
function loadGalleryImage(src){
$("#galleryimage img").on('load', function(){
$(this).css({marginTop: -($(this).height()/2), marginLeft: -($(this).width()/2)});
$("#galleryimage").animate({opacity:1}, 200);
$("#galleryimage img").off('load');
});
$("#galleryimage img").attr('src', src);
}
function hideGalleryImage(){
$("#galleryimage").animate({opacity:0}, 200);
}
</script>
</html>
This uses a few techniques. In CSS the image is absolutely positioned and placed at the 50% point for both top and bottom. Then, using jQuery, once we know the image is loaded, we can determine its width and height, and shove it left and up by half those values. That places it directly in the center of the screen. I added some animation stuff in there for prettiness :)
You can use display:table-cell to vertically align something in the middle. You have to get the div to stretch to 100% of your fixed position div though. I have made a quick jsfiddle:
http://jsfiddle.net/fm2GD/2/
Basically you have to have the image in a table cell:
#tableCell{
height: 100%;
width: 100%;
display:table-cell;
text-align:center;
vertical-align:middle;
}
which is in a "table" :
#table{
height: 100%;
width: 100%;
display:table;
}
which covers 100% of your fixed position div.

How to have a top margin that's a certain percent of window height?

I would like to ask for help with a specific issue. I've searched for similar questions, but haven't found any actual solutions. I'm rather new to CSS.
I'm trying to have a blue box called buttoncontainer that will have buttons in it later on. For now, I would like to format it so that the distance between the top edge of the browser window and the top edge of the blue box is always 42% of the window's total height. As the code below shows, I'm trying to achieve this by giving the box a top margin of 42%.
However, I can't do it. When I open the HTML file in Firefox or IE (which are what I have on my home desktop), the distance is clearly something different when the window is full screen. If it isn't and I start resizing it, the location of the box does NOT respond to vertical resizing at all. It does, however, respond to horizontal resizing, which I don't want it to do.
I imagine this MUST be a rookie mistake I'm making, but I just can't figure out how to get it right.
To reiterate, I want the distance between the top edges of the window and the blue box to always be 42% of the total window height.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" src="jquery-1.9.0.js"></script>
<style type="text/css">
body {
background-color: #C94735
}
iframe {
background-color: #FFF;
border: 0;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 63%;
height: 100%;
margin-left: 25%;
margin-right: 12%;
}
.buttoncontainer {
background-color: #00F;
border: 0;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin-top: 42%;
/* margin-bottom: auto; */
margin-left: 15px;
width: 25%;
height: 58%;
}
</style>
</head>
<body>
<div id="container" class="buttoncontainer">
</div>
<iframe id="content"></iframe>
</body>
</html>
A porcentual value for margin-top will be allways computed against the width of the containing element. Thats why your relative margin position is modified when the width of the viewport/container element is modified.
You could compute with javascript the value and assigned appropriately.
You could try as well (only css level 3) using viewport relative units. ( 1vw = 1% of viewport width and 1vh = 1% of viewport height)
Solution working here in this fiddle where i modified buttoncontainer class as so;
.buttoncontainer {
....
....
margin-top: 42vh;
}

Set HTML Canvas as page background

I've made a JS animation that I want to be the background of my homepage: http://geotheory.co.uk/. But I'm quite new to web development and unclear how to stop the canvas element being an 'inline' object on the page and set it behind other HTML elements. Very grateful for advice. The HTML is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>geotheory.co.uk</title>
<style>
canvas:focus{outline:none;}
* {
margin: 0;
padding: 0;
}
h1 {color:#fff;}
p {color:#fff;}
</style>
</head>
<body id="home" bgcolor="black">
<!-- style="overflow:hidden;" -->
<h1>Heading</h1>
<p>paragraph 1</p>
<p>paragraph 2</p>
<script src="processing-1.4.1.min.js"></script>
<div id="canvasContainer">
<canvas data-processing-sources="rectangles.pde"></canvas>
</div>
</body>
In 2018 I'd use
html, body {
margin: 0;
height: 100%;
}
canvas {
width: 100%;
height: 100%;
display: block;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
Here's why:
I used to recommend canvas { width: 100vw; height: 100vh; ...} but sadly mobile browsers broke vh so it's useless and will apparently be useless forever. See this blog post.
display: block; fixes some issues with scrollbars on certain browsers. Some pages use html, body { overflow: none; } but again that doesn't make sense if your page ends up needing to be taller than the screen/window.
position: fixed; makes the canvas position relative to the top of window so it won't scroll with the page. If you use position: absolute then the canvas will scroll off the top if the page is taller than the screen/window. For example this page.
top: 0; left 0; puts it at the top left. Without that it would default to it's default position which is inside the body's margins. Often this is solved by setting body { margin: 0; } but generally that means you end up needing some other container to add a margin back in otherwise your normal content gets positioned at the edge of the window.
z-index: -9999; is there to try to force it further back than anything else just in case the page itself is using some negative values for z-index
Here's an example as a snippet
var ctx = document.querySelector("canvas").getContext("2d");
function resize(canvas) {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (width != canvas.width || height != canvas.height) {
canvas.width = width;
canvas.height = height;
}
}
function render(time) {
time *= 0.001;
resize(ctx.canvas);
ctx.save();
var w = ctx.canvas.width;
var h = ctx.canvas.height;
var hw = w / 2;
var hh = h / 2;
ctx.clearRect(0, 0, w, h);
ctx.strokeStyle = "red";
ctx.translate(hw, hh);
ctx.rotate(time * 0.1);
for (var ii = 0; ii < 100; ++ii) {
ctx.rotate(Math.sin(time * 0.1) * 0.2);
ctx.strokeRect(-hw, -hh, w, h);
ctx.scale(0.9, 0.9);
}
ctx.restore();
requestAnimationFrame(render);
}
requestAnimationFrame(render);
html, body {
margin: 0;
height: 100%;
}
canvas {
width: 100%;
height: 100%;
display: absolute;
position: fixed;
top: 0;
left: 0;
z-index: -9999;
}
<canvas></canvas>
<pre>
some content that is in front of the canvas
Let's
try
to
make
sure
it's
long
enough
that
we
can
scroll
down
the
page
so
we
can
see
that
position: fixed;
is
a
better
choice
than
position: absolute;
</pre>
And here's an example outside SO so you can view it easier full size.
iframes work as well
Note that there's the issue that if your canvas animation is interactive the elements in front of the canvas will eat the mouse/touch events. There's no easy solution I know of for that. You can mark everything but that canvas/iframe as pointer-events: none and mark the canvas/iframe as pointer-events: auto but then you run into the issue that no text on your page can be selected and no links can be clicked. You could then say set <a> tags to have pointer-events: auto so links work but I'm sure there will be issues here and there depending on what info is on your page (trying to copy an email address, or a location address, etc...)
canvas {
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:-1;
}

Resources