I'm working on an HTML5 browser game that can be divided into 3 parts: two UI panels on the left and right of a center set of square canvases for the playing surface. The three panels need to be horizontally aligned, and the total game needs to keep an aspect ratio of 16:9. The left and right panels should be of equal widths, and all three panels must be of equal height. I have specified a minimum width and height inside a resize() function called when an onresize event is detected.
Currently, each panel is a div, and all three are contained inside a section. Right now, the section isn't necessary, but I want to keep the game separated from extra content at the bottom of the screen that I might choose to add later.
The CSS style is as follows:
* {
vertical-align: baseline;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
font-size: 100%;
border: 0 none;
outline: 0;
padding: 0;
margin: 0;
}
#gameSection {
white-space: nowrap;
overflow-x: hide;
overflow-y: hide;
}
#leftPanel, #centerPanel, #rightPanel {
display: inline-block;
}
#leftPanel {
background-color: #6495ed;
}
#centerPanel {
background-color: #e0ffff;
}
#rightPanel {
background-color: #b0c4de;
Right now, I have set the background color of each div just to show me when I'm correctly setting the size of each div.
The body of my HTML document is as follows:
<body onresize="resize()">
<section id="gameSection">
<div id="leftPanel">Left Panel.</div>
<div id="centerPanel">Center Panel.</div>
<div id="rightPanel">Right Panel.</div>
</section>
</body>
And finally, my resize() function (I created a separate function for resizing the game in case I add more elements below later):
function resize() {
var MIN_GAME_WIDTH = 800;
var MIN_GAME_HEIGHT = 450;
var GAME_ASPECT_RATIO = 16 / 9;
var width = window.innerWidth;
var height = window.innerHeight;
var gWidth, gHeight;
if(width < MIN_GAME_WIDTH || height < MIN_GAME_HEIGHT) {
gWidth = MIN_GAME_WIDTH;
gHeight = MIN_GAME_HEIGHT;
}
else if ((width / height) > GAME_ASPECT_RATIO) {
<!-- width is too large for height -->
gHeight = height;
gWidth = height * GAME_ASPECT_RATIO;
}
else {
<!-- height is too large for width -->
gWidth = width;
gHeight = width / GAME_ASPECT_RATIO;
}
resizeGame(gWidth, gHeight, GAME_ASPECT_RATIO);
}
function resizeGame(var gWidth, var gHeight, var aspectRatio) {
var gSection = document.getElementById("gameSection");
var lPanel = document.getElementById("leftPanel");
var cPanel = document.getElementById("centerPanel");
var rPanel = document.getElementById("rightPanel");
gSection.height = gHeight;
gSection.width = gWidth;
<!-- should the below be taken care of in the CSS? -->
lPanel.height = gHeight;
cPanel.height = gHeight;
rPanel.height = gHeight;
cPanel.width = cPanel.height;
lPanel.width = (gWidth - cPanel.width) / 2;
rPanel.width = lPanel.width;
}
I've tried a number of different commands to resize the divs, but it just isn't working for me. When I try adding test canvases, color appears, but the boxes still aren't the correct size. I have also considered loading an invisible background image to each div and scaling it to the desired size; however, I was able to resize my canvas using the above method before and it seemed to work just fine.
Additional Notes
While I've already had pretty good success resizing a single canvas, I don't want to use just one canvas for the game because not all parts of the UI need to be drawn at the same time.
I'm trying to keep this solely in Javascript.
I suspect that I could just use CSS to handle resizing by fixing the aspect ratio to 16:9 and using width:56.25% for the center panel and width:21.875% for the side panels, but that limits me to one aspect ratio and doesn't explain why my above script isn't working.
I can provide the entire HTML file if needed. This is what it's supposed to look like:
End Goal (without right panel)
Thank you!
UDPATE:
jsfiddle
I got it kind of working here. I made a lot of changes/minor fixes to the code before finding what was wrong (other than various syntax errors):
You were using .width and .height instead of .style.width and .style.height, and you were applying integers to these instead of strings with "px" appended to them. Both of these things are completely understandable to miss.
I also moved the onresize from the body tag into the JS, don't know why it wasn't working on jsfiddle, but this is good practice anyways.
In the future: learn how to debug JS using the console and when you ask questions, use small examples, not your entire codebase. This question could have been simplified to "How do I resize a div?" with one line of JS and one div. You also should consider not doing this specific thing in JS, and using flexbox as redbmk said.
Related
I have 2 divs, a navigation and a main content in a bootstrap grid system. The length of either can vary depending on amount of content. I need them both styled to fill 100% of the browser window IF neither has the content to reach the bottom naturally. But if at least one of the divs has more content than the length of the browser window, I need to be able to scroll down the page with the styles of both divs remaining in tact and both have a height of the longer of the 2 divs.
I'm currently using a javascript resize function which seems to work but not in the case where neither div is long enough to fill the height of the browser window. Any suggestions?
HTML
<div class="row">
<div id="nav" class="col-xs-2">
Variable Height Navigation
</div>
<div id="main" class="col-xs-10">
Variable Height Content
</div>
</div>
Javascript
function resize() {
var h = (document.height !== undefined) ? document.height : document.body.offsetHeight;
document.getElementById("nav").style.height = h + "px";
}
resize();
window.onresize = function () {
resize();
};
I am trying to understand you question, and if I'm correct what you are looking for is:
Both divs need to be equally high
They need be at least the height of the screen
They need to take the height of the highest div
So let's try to achieve this goal as simply as possible:
var main = document.getElementById('main');
var nav = document.getElementById('nav');
function resize(){
var highest;
// Set the divs back to autosize, so we can measure their content height correctly.
main.style.height = 'auto';
nav.style.height = 'auto';
// Find the highest div and store its height.
highest = main.clientHeight > nav.clientHeight
? main.clientHeight
: nav.clientHeight;
// Check if the highest value is the div or the window.
highest = highest > window.innerHeight
? highest
: window.innerHeight;
// Assign the newly found value
main.style.height = highest + 'px';
nav.style.height = highest + 'px';
}
resize();
// Also, you don't need to wrap it in a function.
window.resize = resize;
// However, better would be:
window.addEventListener('resize', resize, false);
#main, #nav {
width: 100%;
height: auto;
}
#main { background: red; }
#nav { background: green; }
<div id="main"></div>
<div id="nav"></div>
Now, If you aren't bothered with the actual sameness in heiught of both divs but just want them to at least be one screenful, you should consider using CSS:
html, body { height: 100%; }
#nav, #main { min-height: 100%; }
I think that is the better solution (no Javascript!) and sort-of does what you want, bar the fact that you won't have to equally high div elements. However, you would barely notice it as each will at least fill the page.
You could try using viewport height:
For example:
#nav {
min-height: 100vh;
}
#main {
min-height: 100vh;
}
See Bootply.
This will also remove the need for JavaScript.
I'm making a website for my art gallery. Part of what I need to do is display images to the viewers in a way in which they can view them. And I want to do this without reducing the quality of the images, or having to save all of my images in many different sizes to cater to every user.
So, I've made a Javascript function to resize my images to fit completely on the viewer's screen. My code looks like
<img src="[image.png]" onload="setGoodHeight(this);">
where the function setGoodHeight(element) is defined as:
function setGoodHeight (element) {
if(window.innerHeight-50 < element.height) {
var h = element.height;
var w = element.width;
element.height = window.innerHeight - 50;
element.width = w * element.height / h;
}
if (window.innerWidth-100 < element.width) {
var h = element.height;
var w = element.width;
element.width = window.innerWidth - 100;
element.height = h * element.width / w;
}
}
In shorthand, this first checks whether the image is higher than the screen it's trying to be displayed on, and if it is (it usually is) the image is resized to fit comfortably on the screen. Then it checks if, after this, the image is wider than the screen, and if so it shrinks it further. I have verified that this code works.
However, the image is contained within a class called .post I want the post area to wrap to that of the image, at least in width, and so at the end of my javascript function, I added this code:
element.parentNode.width = element.width + 40;
But the post doesn't resize itself. For reference, the code on the actual webpage concerning this can be boiled down to
<div class="post">
<img src="[image.jpg]" onload="setGoodHeight(this);">
</div>
and if you need to look around it a little more it can be found at this link.
How about a pure CSS solution, it will also update magically if the user resizes their browser.
html, body, #fullscreen {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#fullscreen {
background: url('http://www.nathanrouse.org/wp-content/uploads/2014/01/CrashTestDummy.jpg') center center no-repeat;
background-size: cover;
}
<div id="fullscreen"></div>
Check the doc for background-size. There are other values like "contain" that might suit you better.
I think you're looking for
item.naturalHeight
item.naturalWidth
I was using these in a function to set the max-height & max-width
function imageLoad(item) {
$(item).attr("max-height", item.naturalHeight);
$(item).attr("max-width", item.naturalWidth);
}
I have two working JSFiddle which I want to combine and work together.
JSFiddle-1 : http://jsfiddle.net/MYSVL/3050/
window.onresize=function() {
var child = $('.artist');
var parent = child.parent();
child.css('font-size', '18px');
while( child.height() > parent.height() ) {
child.css('font-size', (parseInt(child.css('font-size')) - 1) + "px");
}
Here the text inside artist container is responsive and its stretching to maximum font size when the screen is bigger. Its also shrinking to smallest font size when screen size is smaller.
JSFiddle-2 : http://jsfiddle.net/MYSVL/3047/
function calcDivHeights() {
window.onresize=$(".artist").each(function () {
var child = $(this);
var parent = child.parent();
//child.css('font-size', '18px');
while (child.height() > parent.height()) {
child.css('font-size', (parseInt(child.css('font-size')) - 1) + "px");
}
});
}
Here the function is checking for every artist div and adjusting the font size according to the while condition but I am unable to make it responsive like my JSFiddle-1 . Once the text size is smaller it remains smaller even I make the screen bigger. I want my JSFiddle-2 to work exactly as JSFiddle-1 so that I can maintain the responsiveness of the text according to screen size.
Can someone please help me out or feel free to modify my JSFiddle-2 in order to achieve the goal.
Thanks in advance
I can't see differences between your two fiddles except for the commented child.css('font-size', '18px'), both should do the same thing.
Your second fiddle seems to not works properly because once you resize window to a smaller resolution, child becomes smaller or equal to parent. Then, when you return on bigger resolution, you call again while( child.height() > parent.height() ), but now your child height is not greater than your parent height.
I think the following will just do what you're asking for:
$(document).ready(function () {
function adjustFontSize() {
var child = $('.artist');
var parentHeight = child.parent().height();
while( child.height() > parentHeight ) {
child.css('font-size', (parseInt(child.css('font-size')) - 1) + "px");
}
while( child.height() < parentHeight ) {
child.css('font-size', (parseInt(child.css('font-size')) + 1) + "px");
}
};
adjustFontSize(); // Call it when document is ready
window.onresize = adjustFontSize; // Call it each time window resizes
});
.artist-container {
width: 20%;
height: 40px;
border: 1px solid black;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="artist-container">
<div class="artist">Audhit Audhit Audhit Audhit Audhit Audhit Audhit</div>
</div><br>
<div class="artist-container">
<div class="artist">Lorem</div>
</div><br>
I think the CSS media queries approach is so much better for making a web responsive, than calculating everything with Javascript all the time.
For example, you can think about three sizes:
Phone (lets say, 400px width)
Tablet (lets say, 800px width)
Computer (lets say, >800px width)
One way of achieving this, using the desktop first approach, would be:
/* DESKTOP */
body {
font-size: 1em;
...
}
...
/* General rules for desktop
...
/* TABLET */
#media screen and (max-width:800px and min-width:400px) {
/* Overwrite the rules you want to change */
body {
font-size: .75em;
}
...
}
/* PHONE */
#media screen and (max-width:400px) {
/* Overwrite the rules you want to change */
body {
font-size: .75em;
}
#div1 {
height: 20%;
}
...
}
In addition to this, don't forget to work with relative units (em, vw, vh, rem...) and percentages.
Here you have a really good link about responsive design.
I'm using bxslider to have a carousel of images. The thing is though, the images it receives to display are of somewhat unpredictable sizes. The container size is 243x243. And we know that no image will have a side smaller than 243. So...I'd like to center the image in the container. And either zoom in until the shorter of the two dimensions (L vs W) fills the container at 243, and the longer dimension overflow is hidden.
For the images I'm working with, doing this will be perfect for getting the important details of the picture in the frame.
But I'm having trouble...
I've tried the following to center the picture in the frame:
jQuery(".bx-container").each(function() {
var img_w = jQuery(this).children("img").width();
var img_h = jQuery(this).children("img").height();
var pos_top = (img_h - containerHeight) / 2;
var pos_left = (img_w - containerWidth) / 2;
var pos_top = (243 - img_h) / 2;
var pos_left = (243 - img_w) / 2;
jQuery(this).children("img").css({
'top' : pos_top + 'px',
'left' : pos_left + 'px'
});
});
And I've tried this to position not square images into the frame:
jQuery(".bx-container").each(function(){
var refRatio = 1;
var imgH = jQuery(this).children("img").height();
var imgW = jQuery(this).children("img").width();
if ( (imgW/imgH) < refRatio ) {
jQuery(this).addClass("bx-portrait");
} else {
jQuery(this).addClass("bx-landscape");
}
});
});
I've messed with both scripts and the css but I just can't seem to get it work. It either centers but doesn't resize right. Or resizes but centers wrong. Or does both wrong.
Here's the jsfiddle: http://jsfiddle.net/vgJ9X/298/
Could someone help me out?
Thanks!
EDIT:
New jsfiddle...the portrait ones work right. The landscape images still squish. :(
http://jsfiddle.net/vgJ9X/307/
EDIT:
I THINK it has something to do with relatively positioned elements not being allowed to overlap. Trying to find a fix. If anyone knows, edit the last fiddle I posted.
jQuery(".bx-container img").each(function () {
var w = jQuery(this).width();
var h = jQuery(this).height();
if (w > h) $(this).addClass('bx-landscape');
else $(this).addClass('bx-portrait');
});
Check this Updated JSFiddle
Update
jQuery(".bx-container img").each(function () {
var w = jQuery(this).width();
var h = jQuery(this).height();
if (w > h){
$(this).addClass('bx-landscape');
var trans= -243/2;
$(this).css('-webkit-transform','translateZ('+trans+'px)');
}
else if(h > w){
$(this).addClass('bx-portrait');
var trans= -243/2;
$(this).css('-webkit-transform','translateY('+trans+'px)');
}
});
check this JSFiddle
Update of Update
Found the issue with landscape, the plugin is setting max-width:100%; overriding it with max-width:none; fixes the issue...
Update Of Updated Fiddle
Try this:
img{
position:relative;
height:100%;
width:300px;
}
Simple an clean.
Demo: http://jsfiddle.net/vgJ9X/302/
I did a couple things to your jsfiddle.
First I changed the order of your resize and center functions, so the resize comes first. This way, the smaller images get resized, then centered. I also uncommented the first portion of your code.
You also had a couple of errors in your css. There was an extra closing bracket after img style declaration. Your .bx-portrait img and .bx-landscape img declarations were set to 100%px;.
Update:
Change the css in your two .bx classes to:
.bx-portrait img {
height: 100%;
width: auto;
}
.bx-landscape img {
height: auto;
width: 100%;
}
And add a clearfix to your ul:
.bxslider:after {
content: '';
clear: both;
display: table;
padding: 0;
margin: 0;
}
The height is clipping because .bx-viewport has a set height of 243px but also has a 5px border, which makes the actual internal height 233px. You'll need to make the height 253px to account for the 10px of border. This is why they don't look centered vertically.
DEMO
Why don't you just use background images instead and center them. Here is a demo from your original code
http://jsfiddle.net/8y8df/
If you want to show the full size image, just remove the background-size:contain; from the css.
How do I get rid of that undesired white border on the right of the page?
The website basically dynamically resizes images on a grid, here's a video: https://vine.co/v/h2wtnw6K3H0
CSS:
body {
height: 100%;
width: 100%;
margin: 0;
}
grid {
height: 100%;
width: 100%;
}
.gridImage {
vertical-align: bottom;
margin-left: 0px;
margin-right: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
JS:
function resize() {
console.log($(window).width());
var newBody = "";
for (var i = 0; i <= 100; i++) {
newBody += '<img class="gridImage" src="Images/image2.jpg" width="' + $(window).width() / Math.floor(($(window).width() / 100)) + 'px" height="' + $(window).width() / Math.floor(($(window).width() / 100)) + 'px">';
}
document.getElementById("grid").innerHTML = newBody;
}
If my margins are zero, why is this showing up? Anything I'm missing? Thanks.
Ridcully has covered what the problem is, but here’s a solution.
First you would need to calculate the desired width of each image. This is simply your current equation wrapped in Math.ceil().
var windowWidth = $(window).width() // A slight performance improvement, plus cleaner code
var maxImageWidth = <your value here>
var unroundedImageWidth = windowWidth / Math.floor(windowWidth / maxImageWidth)
var roundedImageWidth = Math.ceil(unroundedImageWidth)
Unless your images fit perfectly, this will make each row slightly wider than the window, causing the final image on each line to wrap to the next. To prevent this, you need to set the gridContainer’s width to that of each row.
$('.gridContainer').width(windowWidth * roundedImageWidth / unroundedImageWidth)
Everything should look good, except for one thing: the horizontal scrollbar. This is easily fixed, however. Add this to your CSS:
.gridContainer {
overflow-x: hidden;
}
This will hide both the scrollbar and the final few pixels on each line. Perfect! Well, not quite.
The problem with this method is that one image per row takes the hit (loses pixels) for all of the others. If you have small images and a lot of images per row, you could end up losing a significant portion of your final column.
To avoid this, you can round your image widths upwards and distribute the overflow amongst all images in the row. This is a little more complicated than the previous method, but it does give a better result.
There are three more numbers you need to calculate.
var imagesPerRow = windowWidth / unroundedImageWidth
var numOfRows = Math.ceil($('.gridContainer img').length / imagesPerRow)
var spillage = windowWidth / roundedImageWidth - windowWidth // Pixels we have to lose
Now it’s just a matter of distributing the spillage.
var i = 0 // Loop counter
while (spillage !== 0) {
// Set the width of all images in column i to the width of that column - 1
$('.gridContainer img:nth-child(' + imagesPerRow + 'n-' + (i+1) + ')')
.width($('.gridContainer img:nth-child(' + (i+1) + ')').width() - 1)
spillage--
i++
}
There should no longer be more than a single pixel difference between the widths of the images.
It's because of rounding errors. What you do is fill the grid with 100 scaled images, depending on the browser to wrap to a new line when the image doesn't fit in the current row any more.
Now imagine a width of 305 pixels. Your formula gives an image width of 100 for that, so you get 3 images in a row and the next one wraps to the next row, leaving 5 pixels blank at the right border.
i think you should also add padding:0; to body its missing from your code.
Try it and even better just make a jsfiddle then it would be easier to check for everyone.