I have to create a web page that for the purposes of this question is a single image centered both vertically and horizontally in the center of the screen. It has the following requirements:
The screen size of the client is unknown (mobile)
The image is user-defined and therefore is of unknown dimensions
The image must be perfectly centered both vertically and horizontally on all devices
The image centering must persist through a screen rotation (i.e. from portrait to landscape)
Being a bit of a CSS newb, I went and created this the only way I knew how, using javascript to position the content:
http://jsfiddle.net/error454/8YL9a/
I'm looking for a solution that functions identically to my solution but uses CSS instead of hard equations.
display:-webkit-box;
-webkit-box-orient:horizontal;
-webkit-box-pack:center;
-webkit-box-align:center;
display:-moz-box;
-moz-box-orient:horizontal;
-moz-box-pack:center;
-moz-box-align:center;
CSS3 property, bad support : webkit, mozilla. Only way to do it with clean markup and CSS without JS.
edit 1 : http://jsfiddle.net/t8qtn/6/
edit 2 : for future proofing, the prefixless version is
display:box;
box-orient:horizontal;
box-pack:center;
box-align:center;
This is a nice article on centering: http://www.w3.org/Style/Examples/007/center.en.html
It should be something like:
.vcenter { display:table-cell; vertical-align:middle; }
.hcenter { display:block; margin-left:auto; margin-right:auto; }
And then apply both classes to your image:
<img class="vcenter hcenter" src="..."/>
Update: you could simply use a table like here http://www.sorinvasilescu.ro/
Related
I have some text inside a <p> that is inside a <div>. I have a css image shape that floats to one side. I want the text in the two upper boxes to wrap to the shape but also align to the bottom of the div. The two lower boxes work fine because I do not need to vertically align the text within them. The problem is, the text can vary in length and so can the amount of lines, so I can not use a fixed height. Therefore absolute positioning will not work, plus the text will ignore my floating css image shape.
I have read dozens of questions and answers and all of them seem to use hacks. There is also one question that seems to ask the same as mine, but I can't find it anymore, besides there was only one answer which was javascript based. I tried using flexboxes with align-items:flex-end; but that doesn't work well with my floating shapes. I also tried using a table and vertical-align:bottom; but my text just breaks to another line and doesn't wrap to the shape.
A workaround I came up with is to use padding-top on the text, but not knowing the height of the text means the text does not always position it to the bottom of the div, especially if the length of text changes.
EDIT: I am totally open to any new ideas. This was just the best approach I could come up with. I even started toying around with the idea of using only one shape for all four boxes. But that seems a bigger challenge.
EDIT: I also updated the URL's so you can now run the code snippet.
EDIT: I have decided to go the Javascript route and am working on a solution. I am open to any ideas.
EDIT: What bothers me the most, is that every single idea I come up with requires an army of Javascript. The solution, in my opinion, should NOT require a nightmare. CSS should be able to solve this, but I can't seem to find a way without Javascript.
div, img, p {
margin:0px;
border:0px;
padding:0px;
}
#wrapper {
display:block;
position:absolute;
left:0px;
top:0px;
width:100%;
height:100%;
}
.box {
display:block;
position:absolute;
width:50%;
height:50%;
}
.box p { line-height:1.5em; padding:10px; }
/* The image shape is 300px x 300px. * /
/* I use 50vh because I want the shape size to always be half of the window height. */
/* This gives the illusion of one larger shape. */
.shape {
position:relative;
shape-margin:2em;
width:50vh;
height:50vh;
}
/* My workaround solution - #top_left p, #top_right p { padding-top:29vh; } */
#top_left { right:50%; top:0%; }
#bottom_left { right:50%; top:50%; }
#top_right { left:50%; top:0%; }
#bottom_right { left:50%; top:50%; }
#top_left p, #bottom_left p { text-align:right; }
#top_right p, #bottom_right p { text-align:left; }
#top_left .shape { float:right; shape-outside:url('https://i.stack.imgur.com/B1Dzu.png'); }
#bottom_left .shape { float:right; shape-outside:url('https://i.stack.imgur.com/Vxmz0.png'); }
#top_right .shape { float:left; shape-outside:url('https://i.stack.imgur.com/UL8uT.png'); }
#bottom_right .shape { float:left; shape-outside:url('https://i.stack.imgur.com/EGBRz.png'); }
<div id="wrapper">
<div id="top_left" class="box">
<img src="https://i.stack.imgur.com/B1Dzu.png" class="shape" />
<p>Here is some text. Here is some text. Here is some text.</p>
</div>
<div id="top_right" class="box">
<img src="https://i.stack.imgur.com/UL8uT.png" class="shape" />
<p>Here is some text. Here is some text. Here is some text.</p>
</div>
<div id="bottom_left" class="box">
<img src="https://i.stack.imgur.com/Vxmz0.png" class="shape" />
<p>Here is some text. Here is some text. Here is some text.</p>
</div>
<div id="bottom_right" class="box">
<img src="https://i.stack.imgur.com/EGBRz.png" class="shape" />
<p>Here is some text. Here is some text. Here is some text.</p>
</div>
</div>
I have created an image to illustrate. The pink borders are just to show the box boundaries.
shape_top_left.png
shape_top_right.png
shape_bottom_left.png
shape_bottom_right.png
The best you will probably achieve is through using the shape-outside property
Check out here for some documentation.
However, be warned as of 2019 this isn't supported in Internet Explorer or Microsoft Edge
A simple enough codepen example would be this
Well here is my Javascript solution. It requires a lengthy script so I will just get to the core of the solution.
The Workaround
With my CSS image shape floating to the right I can still get wrapping text, even though I want my text to align to the bottom. Since no working spec I have seen allows me to vertically align my text to the bottom and get it to wrap to a CSS shape, I need to create the illusion with padding-top. I solved the dilemma of not knowing my text height by running a series of checks through a loop in Javascript. Just check the initial height of the text, then add a single increment of padding-top, then compare with the parent container's height. Repeat this process until the text height reaches or exceeds the parent containers height. The important thing here is that each time you add an increment of padding-top, you change the height of the text. The more padding you add, and the closer the text gets to the CSS shape, the more the text wraps and flows differently. This is why we need to check the height on each increment. Since my text has a font size in EM units, I would have a hard time knowing it's computed height doing guesswork. Add in client zooming and it's a math nightmare! Rather we just check with single increments and no math needed, hooray!
My Javascript
This is just a core example, not the full script, but you should get the idea.
var counter = 0 ;
function checkHeight()
{
var container = document.getElementById("top_left") ;
var text = document.getElementById("top_left_text") ;
var container_height = container.offsetHeight ;
counter++ ;
text.style.paddingTop = counter + "vh" ;
var text_height = text.offsetHeight ;
if ( text_height < container_height ) { checkHeight() ; }
}
Another Future Solution
Using CSS Exclusions.
With CSS Exclusions you can have an element that does not float but, behaves like a floating element, so that content wraps around the element in much the way that floating elements do. Unfortunately, there is almost no support for this technology at the moment. That said, I would strongly encourage anyone interested to join the discussion and get more buzz going for the draft to maybe become a real spec. CSS Exclusions open up some really cool possibilities that, in my opinion, bring HTML out of the stone age in terms of document flow.
In the case of my problem here, I would simply be able to absolutely position my CSS image shape and get my layout without the need of Javascript. My text would be vertically aligned to the bottom because there would be no floats to say otherwise.
For those who want to know more about CSS shapes, read this excellent article.
I would like to use media queries to resize elements based on the size of a div element they are in. I cannot use the screen size as the div is just used like a widget within the webpage, and its size can vary.
Yes, CSS Container Queries are what you're looking for. The CSS Containment Module is the specification that details this feature.
You can read more about the decade of work, including proposals, proofs-of-concept, discussions and other contributions by the broader web developer community here! For more details on how such a feature might work and be used, check out Miriam Suzanne's extensive explainer.
Currently only Chromium 105+ supports Container queries out of the box, though Safari 16 will include support as well. Hopefully it won't be much longer before we see a robust cross-browser implementation of such a system. It's been a grueling wait, but I'm glad that it's no longer something we simply have to accept as an insurmountable limitation of CSS due to cyclic dependencies or infinite loops or what have you (these are still a potential issue in some aspects of the proposed design, but I have faith that the CSSWG will find a way).
Media queries aren't designed to work based on elements in a page. They are designed to work based on devices or media types (hence why they are called media queries). width, height, and other dimension-based media features all refer to the dimensions of either the viewport or the device's screen in screen-based media. They cannot be used to refer to a certain element on a page.
If you need to apply styles depending on the size of a certain div element on your page, you'll have to use JavaScript to observe changes in the size of that div element instead of media queries.
Alternatively, with more modern layout techniques introduced since the original publication of this answer such as flexbox and standards such as custom properties, you may not need media or element queries after all. Djave provides an example.
I've just created a javascript shim to achieve this goal. Take a look if you want, it's a proof-of-concept, but take care: it's a early version and still needs some work.
https://github.com/marcj/css-element-queries
From a layout perspective, it is possible using modern techniques.
Its made up (I believe) by Heydon Pickering. He details the process here: http://www.heydonworks.com/article/the-flexbox-holy-albatross
Chris Coyier picks it up and works through a demo of it here: https://css-tricks.com/putting-the-flexbox-albatross-to-real-use/
To restate the issue, below we see 3 of the same component, each made up of three orange divs labelled a, b and c.
The second two's blocks display vertically, because they are limited on horizontal room, while the top components 3 blocks are laid out horizontally.
It uses the flex-basis CSS property and CSS Variables to create this effect.
.panel{
display: flex;
flex-wrap: wrap;
border: 1px solid #f00;
$breakpoint: 600px;
--multiplier: calc( #{$breakpoint} - 100%);
.element{
min-width: 33%;
max-width: 100%;
flex-grow: 1;
flex-basis: calc( var(--multiplier) * 999 );
}
}
Demo
Heydon's article is 1000 words explaining it in detail, and I'd highly recommend reading it.
Update 2021/22
As mentioned in other answers, container queries are coming. There is a full spec for it, and its usage is detailed on MDN:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
and there is a polyfill to get browsers that don't yet support it up to speed:
https://github.com/GoogleChromeLabs/container-query-polyfill
There is a nice little overview video of it here:
https://www.youtube.com/watch?v=gCNMyYr7F6w
This has now shipped to Chrome (05 September 2022)
https://caniuse.com/css-container-queries
A Media Query inside of an iframe can function as an element query. I've successfully implement this. The idea came from a recent post about Responsive Ads by Zurb. No Javascript!
This is currently not possible with CSS alone as #BoltClock wrote in the accepted answer, but you can work around that by using JavaScript.
I created a container query (aka element query) polyfill to solve this kind of issue. It works a bit different than other scripts, so you don’t have to edit the HTML code of your elements. All you have to do is include the script and use it in your CSS like so:
.element:container(width > 99px) {
/* If its container is at least 100px wide */
}
https://github.com/ausi/cq-prolyfill
I ran into the same problem a couple of years ago and funded the development of a plugin to help me in my work. I've released the plugin as open-source so others can benefit from it as well, and you can grab it on Github: https://github.com/eqcss/eqcss
There are a few ways we could apply different responsive styles based on what we can know about an element on the page. Here are a few element queries that the EQCSS plugin will let you write in CSS:
#element 'div' and (condition) {
$this {
/* Do something to the 'div' that meets the condition */
}
.other {
/* Also apply this CSS to .other when 'div' meets this condition */
}
}
So what conditions are supported for responsive styles with EQCSS?
Weight Queries
min-width in px
min-width in %
max-width in px
max-width in %
Height Queries
min-height in px
min-height in %
max-height in px
max-height in %
Count Queries
min-characters
max-characters
min-lines
max-lines
min-children
max-children
Special Selectors
Inside EQCSS element queries you can also use three special selectors that allow you to more specifically apply your styles:
$this (the element(s) matching the query)
$parent (the parent element(s) of the element(s) matching the query)
$root (the root element of the document, <html>)
Element queries allow you to compose your layout out of individually responsive design modules, each with a bit of 'self-awareness' of how they are being displayed on the page.
With EQCSS you can design one widget to look good from 150px wide all the way up to 1000px wide, then you can confidently drop that widget into any sidebar in any page using any template (on any site) and
The question is very vague. As BoltClock says, media queries only know the dimensions of the device. However, you can use media queries in combination with descender selectors to perform adjustments.
.wide_container { width: 50em }
.narrow_container { width: 20em }
.my_element { border: 1px solid }
#media (max-width: 30em) {
.wide_container .my_element {
color: blue;
}
.narrow_container .my_element {
color: red;
}
}
#media (max-width: 50em) {
.wide_container .my_element {
color: orange;
}
.narrow_container .my_element {
color: green;
}
}
The only other solution requires JS.
The only way I can think that you can accomplish what you want purely with css, is to use a fluid container for your widget. If your container's width is a percentage of the screen then you can use media queries to style depending on your container's width, as you will now know for each screen's dimensions what is your container's dimensions. For example, let's say you decide to make your container's 50% of the screen width. Then for a screen width of 1200px you know that your container is 600px
.myContainer {
width: 50%;
}
/* you know know that your container is 600px
* so you style accordingly
*/
#media (max-width: 1200px) {
/* your css for 600px container */
}
You can use the ResizeObserver API. It's still in it's early days so it's not supported by all browsers yet (but there's several polyfills that can help you with that).
This API allows you to attach an event listener when resizing a DOM element.
Demo 1 - Demo 2
I was also thinking of media queries, but then I found this:
http://www.mademyday.de/css-height-equals-width-with-pure-css.html
Maintain the aspect ratio of a div with CSS
Just create a wrapper <div> with a percentage value for padding-bottom, like this:
div {
width: 100%;
padding-bottom: 75%;
background:gold; /** <-- For the demo **/
}
<div></div>
It will result in a <div> with height equal to 75% of the width of its container (a 4:3 aspect ratio).
This technique can also be coupled with media queries and a bit of ad hoc knowledge about page layout for even more finer-grained control.
It's enough for my needs. Which might be enough for your needs too.
For mine I did it by setting the div's max width, hence for small widget won't get affected and the large widget is resized due to the max-width style.
// assuming your widget class is "widget"
.widget {
max-width: 100%;
height: auto;
}
I have the following img tag, which sits inside a container with 30 pixels of horizontal padding. It is therefore designed to show a 640-pixel wide image if the screen is >=670 pixels wide, and otherwise a 320-pixel wide image:
<img srcset="TestImage320.png 320w, TestImage640.png 640w"
sizes="(max-width: 669px) 320px, 640px"
src="TestImage320.png">
However, the 640-pixel image is simply a manually scaled-up version of the 320-pixel image. Is it possible to achieve the same effect without creating (and requiring users to download) the 640-pixel image?
Essentially, my current approach chooses between src="TestImage320.png" and src="TestImage640.png" values depending on the available width. Instead, I want to keep src="TestImage320.png" and choose between style="width: 320px" and style="width: 640px". How can I achieve this (or something equivalent)?
If you try to scale up an image, it will look bad. You can scale down better and still keep some nice quality.
I would only include the 640px version. Throw a max-width: 640px; width: 100%; and watch it scale down perfectly.
Unless you are significantly worried about load time it is often best to use the largest image you need (in your case 640px) and then scale it down to 320px. Keep in mind with the prevalence of retina displays it is recommended that you double the resolution of your image so it still looks nice on those displays. But again it's a load time vs image quality question, though an image at 1280px shouldn't be a super huge file.
Use this style on your image it will scale and keep integrity according to width.
.imageClass{
width:100%
height:auto;
float:left;
}
If you need it to remain a certain height this will keep integrity according to height.
.imageClass{
width:auto;
height:100%;
float:left;
}
File HTML:
<div class="text-img">
<img src="text.jpg" alt="text" title="text" />
</div>
File CSS:
.text-img {width:100%;max-width:640px;overflow:hidden;}
.text-img img {min-height:100%;}
Can we have an image which spans over multiple columns which is created using CSS3 multicolumn property in an Html page. Here is my column layout style
div#column {
margin-left:20px;
-moz-column-width: 250px;
-moz-column-gap: 20px;
-webkit-column-width: 250px;
-webkit-column-gap: 20px;
height: 850px;
}
I need to place an image within this column layout which spans over atleast 2 or 3 columns.
Theoretically there is column-span, however it doesn't seem to be supported by any browser currently.
You could try with position:absolute as Simon suggests, but I doubt you will can satisfactory results and I don't think there is any other reasonable workaround.
Maybe there are JavaScript libraries that can do it...
Add a width on your div and add this style
column-count:3;
-moz-column-count:3;
-webkit-column-count:3;
See reference: >>
I asked #Krishna to post this question since our other SO question/answer session Increase font size with JavaScript around fixed floated images in CSS columns was getting off-topic, i.e. it was solved and this image spanning multiple columns warranted a new question.
So, my thoughts so far...
column-span is working in Webkit (Chrome12) for me. Check out the quirksmode demo page. However, the bad news is that it doesn't help solve this problem as the image that needs to span multiple columns still gets clipped at the column-width, so I don't think it is the solution.
For now I think the only solution is to do the columns yourself in JavaScript, or maybe try and use/modify the jQuery columnizer plugin.
Oh and I just found this other question CSS3 Columns and Images which basically agrees that it is impossible without JavaScript.
There is already have a lot of JavaScript for your font increase/decrease (different question, see my fiddle) so it would have been great if CSS supported this natively. All we want is big Yoda to spill over into the second column :-)
So I think that the only solution currently is:
For each image that is greater then the width of a column, work out how much into the next column it would be (including the column-gap)
Add a spacer floating <div> in the next where the image needs to overlap to, so that the words correctly continue to flow around and below the image
Absolutely position a copy of the image over the top.
I just hope you don't want images that span more than 2 columns otherwise it's going to complicate an already complex solution!
Use position:absolute, like this:
#image {
position:absolute;
top:300px; //distance from top
left:200px; //distance from left
width:600px; //image width
height:400px; //image height
}
I have a bunch of images that are guaranteed to have:
minimum width = 200px
maximum width = 250px
minimum height = 150px
maximum height = 175px
What I want to do is display a consist 200px by 150px rectangle of the image while maintaining scale (no stretching or shrinking).
Which means, I might have some overflow.
How can I display the image so that it keeps porpotions to the original image size, yet displayed inside a 200x150 px window and hiding any overflow?
Wrap them in a container with the dimensions you want and overflow: hidden.
This trick is quite cool and doesnt matter the image size ok look... you can do something like this
<div style="width:Npx; height:Npx; overflow:hidden">
<img src="source.png" style="width:Npx;">
</div>
so how this work, the div will hold the imagen in a rectangle Xpx by Ypx you defined and will "crop" everything that its outside. Then you use the resize who have every browser you can assign a With a imagen and the browser will resize it for you. So if you put the same width that the div holder you will give the impresion that the image fit in that rectangle. This is the best option I can find without use server side code.
the next example is:
you can define again a rectangle and then assign a background, the big problem is the the imagen WILL not resize to fit the area.
<div style="width:Npx; height:Npx; background:url(yourimage.png) center"></div>
hope to help you... best
I made a quick demo (online here) of a way of solving it similar to nahum's second example. There are 3 images within the range of sizes you set. It doesn't resize or stretch the images and they will follow the alignment of the surrounding text.
Hope it helps,
Jedidiah
<span class="thumbnail" style="background-image:url(200_150.jpg);"></span>
<span class="thumbnail" style="background-image:url(220_160.jpg);"></span>
<span class="thumbnail" style="background-image:url(250_175.jpg);"></span>
span.thumbnail{
display:block; display:inline-block;
width:200px; height:150px;
background-position: center center;
background-repeat: no-repeat;
}
Use a span rather than a div because IE6+7 will only let you set display:inline-block on an element that is naturally inline.
The first display:block is a fallback for Firefox 2 which doesn't support inline-block.
If you're images are particularly large, or there are going to be lots of them (for example, a thumbnail browser). You may want to consider creating a pre-cropped copy of them image. This can be done using gd or imagemagick [0] - you can also find a number of wrapper libraries around these extensions that may make the task easier.
[0] http://php.net/manual/en/refs.utilspec.image.php
In theory, this is exactly what the clip property of CSS is for - but there's one, sometimes really painful, side effect to using it, though - the image needs to be absolutely positioned:
<html>
<head>
<style type="text/css">
.thumbnail {
width:200px;
height:150px;
}
.thumbnail img {
position:absolute;
clip:rect(0, 200px, 150px, 0);
}
</style>
</head>
<body>
<div class="thumbnail"><img src="http://uhaweb.hartford.edu/SDUNN/sandwich.jpg"></div>
<div class="thumbnail"><img src="http://uhaweb.hartford.edu/SDUNN/sandwich.jpg"></div>
<div class="thumbnail"><img src="http://uhaweb.hartford.edu/SDUNN/sandwich.jpg"></div>
<div class="thumbnail"><img src="http://uhaweb.hartford.edu/SDUNN/sandwich.jpg"></div>
</body>
</html>
The fact that this takes the images out of document flow is pretty nasty - the best you can do is put them inside a frame of the right dimensions (which means you may as well just use the overflow mask methods other people have suggested). Clip is a useful property in the right places, and a lot of people don't seem to know about it.
Just set a min-height:whatever and max-height:whatever and overflow:hidden on the blocks, then just place the images in the block, and that's it.