homepage Welcome to WebmasterWorld Guest from 50.16.112.199
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / CSS
Forum Library, Charter, Moderators: not2easy

CSS Forum

    
Aligning text below images with different dimensions
Text should align horizontally
VuoriLiikaluoma



 
Msg#: 4314025 posted 11:09 am on May 18, 2011 (gmt 0)

Hello, I need some help figuring this one out...
I've got a products page with some blocks containing an image, a title and a price. What I want is for the text under one image to be vertically aligned with the text under the other images on the same row.

Let's get to the code:...

<div class="product block(1-3)">
<div class="product_image">
<img class="product_img" src="pic.png">
</div>
<p>
<span>Title</span>
<span>100.00 </span>
</p>
</div>

And CSS:

div.product
{
width:24%;
display:inline-block;
vertical-align:top;
padding:3% 0;
}

div.block1, div.block3
{
margin:0 6%;
}

div.product_img
{
width:100%
}


Anyhow, the images are all different sizes and are scaled down to fit three products per row. It looks and works OK, but I want the titles and prices to be aligned.
I tried setting a height on div.product_image but then it clipped the image on higher resolutions and created a lot of white-space on lower ones. Quite frankly I'm at a loss for once. I have no idea on how to do this without tables... Maybe I should use tables?

 

kb5nju

5+ Year Member



 
Msg#: 4314025 posted 3:40 pm on May 18, 2011 (gmt 0)

Try taking the <p> tags out? I've done something like this before:

HTML Example:
<div class="imageWrapper"> <div class="imageAndCaptionWrapper">
<img src="image.jpg" class="picborder" alt="Alt Text" width="160" height="378" /><br />
<div class="smallcaption">Blah Blah<br />
Blah Blah</div>
</div>
</div>

CSS Example:

.imageWrapper
{
float:right;
padding: 0px 1px 0px 6px;
}

.imageAndCaptionWrapper
{
padding: 0px;
}

.smallcaption {
font-family: Geneva, Arial, Helvetica, Swiss, sans-serif;
line-height: 13px;
font-size: 11px;
font-weight: bold;
padding: 2px 0px 0px 0px;
}

alt131

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4314025 posted 7:15 pm on May 18, 2011 (gmt 0)

Hi VuoriLiikaluoma [webmasterworld.com] and welcome to WebmasterWorld :)

Maybe I should use tables?
Recalling the goal is to separate content from style (layout), this content is always difficult to classify. IMO it could well be treated as tabular data, but also a list, and some extend that to treating title and price as "explaining" the image and use a definition list (maxdesign has an interesting article).

As kb5nju highlights <p>'s aren't required. I wonder if they were used to achieve block behaviour? The following takes kb5nju idea of reducing code one more step by using a list and display:inline-block, with an overall width set on the <ul> to force the image/title/price sets to wrap so there are only 3 per line. That avoids floats, and a list naturally groups the information sets, plus locks everything inside one "container" for laying out in relation other elements on the page.

cssplay has some interesting examples using display:table/cell to centre images of unknown dimensions, but support is still immature. The only caveat is that a conditional comment is required if supporting ie<8. Although ie adopted inline-block early, only for inline elements (which kinda' makes sense), and <li> are display:list-item by default.


CSS
ul {
margin:0 auto;
padding:0;
width:710px;
list-style-type:none;
}

li {
display:inline-block;
padding:15px;
text-align:center;
width:200px; /*or % for greater flexibility */
}

img, b, a {
display:block;
margin:0 auto;
}
HTML
<ul>
<!--copy 3 times for multiple rows -->
<li><img src="image.jpg" width="100" height="100" alt="My alt"><b>Title</b><a href="#">Price</a></li>
<li><img src="image.jpg" width="10" height="12" alt="My alt"><b>Title</b><a href="#">Price</a></li>
<li><img src="image.jpg" width="180" height="168" alt="My alt"><b>Title</b><a href="#">Price</a></li>
</ul>

VuoriLiikaluoma



 
Msg#: 4314025 posted 7:09 am on May 23, 2011 (gmt 0)

Thanks for the help kb5nju and alt131,
That's close to what I was looking for however the images should have been vertically aligned at the top...
It's this that causes the problem with the text not being aligned.
That's why I was considering using tables...
Though maybe I should use display instead...

Here's a picture of what I want: [bayimg.com...]

alt131

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4314025 posted 1:49 pm on May 23, 2011 (gmt 0)

Hi VuoriLiikaluoma,
Thanks for the feedback. Either of the examples could be modified to achieve the additional aim of aligning the top of the images as well.

Are you able to post the code you're working on so we can discuss/suggest further modifications to help get you there? part of my reasoning is that I certainly think display is a useful "tool" in this situation - but it's hard to make useful suggestions without knowing how you are applying it :)

Regards the references to using tables ... they are always an option, especially as (per my first post), I think this content could easily be dealt with as tabular data. Just that unless it is 100% certain a table is best, this is the forum that tries to use css for layout instead ;)

VuoriLiikaluoma



 
Msg#: 4314025 posted 7:50 am on May 24, 2011 (gmt 0)

The code is part of a theme for PrestaShop and uses Smarty (PHP) in it's template files.
The code below uses a form unlike the code I posted before.
Why do I use a form, well I need to send a crap-load of info between pages in the products hidden input field and then I have some other strings that help with "hacking" PrestaShop to do what I want without modifying the core code.
The previous code was just a general "something like this"-code.
Anyhow, I'd have no problems modifying it to do what I want if only I could figure out how to do it.
Oh and, brace your eyes for some crap-ugly code...

Here's a test-image of the end results: [bayimg.com...]

This is the raw code that I currently have running:

<div id="Blocks">
<h1>{l s='Category Name!'}</h1>
{if !isset($i)}
{$i = 1}
{/if}
{if isset($products)}
<!-- Products list -->
{foreach from=$products item=product name=products}
<div class="ajax_block_product {cycle values="Block1,Block2,Block3"}">
<div class="center_block">
<form action="{$product.link|escape:'htmlall':'UTF-8'}" method="post" accept-charset="utf-8" id="form{$i}">
<div>
<input type="hidden" name="products" value="{$products|serialize|base64_encode}" />
{if isset($prev)}<input type="hidden" name="previous" value="{$prev}" />
{elseif isset($previous)}<input type="hidden" name="previous" value="{$previous}" />{/if}
{if isset($categ_id)}<input type="hidden" name="categ_id" value="{$categ_id}" />{/if}
{if isset($search_query)}<input type="hidden" name="search_query" value="{$search_query}" />{/if}
<input type="image" src="{$img_dir}nyhet.png" class="NyhetImg" alt="{l s="Nyhet!"}"/>
<div class="prod_image">
<input type="image" src="{$link->getImageLink($product.link_rewrite, $product.id_image)}" class="ProdImg" alt="{$product.legend|escape:'htmlall':'UTF-8'}"/>
</div>
<input type="submit" value="{$product.name|truncate:35:'...'|escape:'htmlall':'UTF-8'}" alt="{$product.name|escape:'htmlall':'UTF-8'}" />
</div>
</form>
</div>
<div class="right_block">
{if isset($product.on_sale) && $product.on_sale && isset($product.show_price) && $product.show_price}<span class="on_sale">{l s='On sale!'}</span>
{elseif isset($product.reduction) && $product.reduction && isset($product.show_price) && $product.show_price}<span class="discount">{l s='Reduced price!'}</span>{/if}
{if !$PS_CATALOG_MODE && isset($product.online_only) && $product.online_only}<span class="online_only">{l s='Online only!'}</span>{/if}
{if ((isset($product.show_price) && $product.show_price) || (isset($product.available_for_order) && $product.available_for_order))}
{if isset($product.show_price) && $product.show_price && !isset($restricted_country_mode)}<span class="price" style="display: inline;">{if !$priceDisplay}{convertPrice price=$product.price}{else}{convertPrice price=$product.price_tax_exc}{/if}</span><br />{/if}
{if !$PS_CATALOG_MODE && isset($product.available_for_order) && $product.available_for_order && !isset($restricted_country_mode)}<span class="availability">{if ($product.allow_oosp || $product.quantity > 0)}{l s='Available'}{elseif !$PS_CATALOG_MODE && (isset($product.quantity_all_versions) && $product.quantity_all_versions > 0)}{l s='Product available with different options'}{else}{l s='Out of stock'}{/if}</span>{/if}
{/if}
{if ($product.id_product_attribute == 0 || (isset($add_prod_display) && ($add_prod_display == 1))) && $product.available_for_order && !isset($restricted_country_mode) && !$PS_CATALOG_MODE}
{if ($product.allow_oosp || $product.quantity > 0) && $product.customizable != 2}
<a class="button ajax_add_to_cart_button exclusive" rel="ajax_id_product_{$product.id_product|intval}" href="{$link->getPageLink('cart.php')}?add&amp;id_product={$product.id_product|intval}{if isset($static_token)}&amp;token={$static_token}{/if}" title="{l s='Add to cart'}">{l s='Add to cart'}</a>
{else}
<span class="exclusive">{l s='Add to cart'}</span>
{/if}
{/if}
</div>
</div>
{$i = $i + 1}
{/foreach}
<!-- /Products list -->
{/if}
</div>


Generated HTML:

<div id="Blocks">
<h1>aaaa</h1>
<!-- Products list -->
<div class="ajax_block_product Block1">
<div class="center_block">
<form action="http://example.com/product.php?id_product=2" method="post" accept-charset="utf-8" id="form1">
<div>
<input type="hidden" name="products" value="blah..." />
<input type="hidden" name="previous" value="category" />
<input type="hidden" name="categ_id" value="9" /> <input type="image" src="http://example.com/themes/moblera/img/nyhet.png" class="NyhetImg" alt="Nyhet!"/>
<div class="prod_image">
<input type="image" src="http://example.com/img/p/2-46.jpg" class="ProdImg" alt="iPod shuffle"/>
</div>
<input type="submit" value="iPod shuffle" alt="iPod shuffle" />
</div>
</form>
</div>
<div class="right_block">
<span class="discount">S&auml;nkt pris!</span><span class="price" style="display: inline;">42,57 kr</span><br /></div>
</div>
<div class="ajax_block_product Block2">
<div class="center_block">
<form action="http://example.com/product.php?id_product=7" method="post" accept-charset="utf-8" id="form2">
<div>
<input type="hidden" name="products" value="blah..." />
<input type="hidden" name="previous" value="category" />
<input type="hidden" name="categ_id" value="9" /> <input type="image" src="http://example.com/themes/moblera/img/nyhet.png" class="NyhetImg" alt="Nyhet!"/>
<div class="prod_image">
<input type="image" src="http://example.com/img/p/7-24.jpg" class="ProdImg" alt="iPod touch"/>
</div>
<input type="submit" value="iPod touch" alt="iPod touch" />
</div>
</form>
</div>
<div class="right_block">
<span class="price" style="display: inline;">302,05 kr</span><br /></div>
</div>
<div class="ajax_block_product Block3">
<div class="center_block">
<form action="http://example.com/product.php?id_product=6" method="post" accept-charset="utf-8" id="form3">
<div>
<input type="hidden" name="products" value="blah..." />
<input type="hidden" name="previous" value="category" />
<input type="hidden" name="categ_id" value="9" /> <input type="image" src="http://example.com/themes/moblera/img/nyhet.png" class="NyhetImg" alt="Nyhet!"/>
<div class="prod_image">
<input type="image" src="http://example.com/img/p/6-20.jpg" class="ProdImg" alt=" MacBook Air SuperDrive"/>
</div>
<input type="submit" value="MacBook" alt="MacBook" />
</div>
</form>
</div>
<div class="right_block">
<span class="price" style="display: inline;">1 463,21 kr</span><br /></div>
</div>
<div class="ajax_block_product Block1">
<div class="center_block">
<form action="http://example.com/product.php?id_product=5" method="post" accept-charset="utf-8" id="form4">
<div>
<input type="hidden" name="products" value="blah..." />
<input type="hidden" name="previous" value="category" />
<input type="hidden" name="categ_id" value="9" /> <input type="image" src="http://example.com/themes/moblera/img/nyhet.png" class="NyhetImg" alt="Nyhet!"/>
<div class="prod_image">
<input type="image" src="http://example.com/img/p/5-15.jpg" class="ProdImg" alt="MacBook Air"/>
</div>
<input type="submit" value="MacBook Air" alt="MacBook Air" />
</div>
</form>
</div>
<div class="right_block">
<span class="price" style="display: inline;">1 880,23 kr</span><br /></div>
</div>
<!-- /Products list -->
</div>


And the CSS for that part:

#Blocks input.NyhetImg
{
position:absolute;
}

#Blocks input.ProdImg
{
width:100%;
}

#Blocks div.ajax_block_product
{
width:24%;
display:inline-block;
vertical-align:top;
padding:3% 0;
}

#Blocks div.Block1, #Blocks div.Block3, #Blocks div.block1, #Blocks div.block3
{
margin:0 6%;
}

#Blocks div.ajax_block_product input
{
background-color:transparent;
border:none;
color:inherit;
cursor:pointer;
display:inline;
font-size:0.90em;
font-weight:bold;
margin-bottom:5px;
padding:0;
}

#Blocks div.ajax_block_product div.right_block
{
font-size:0.95em;
font-weight:bold;
text-align:right;
}

#Blocks div.ajax_block_product div.right_block span.discount
{
background-color:transparent;
color:#FF0000;
font-size:1.2em;
font-weight:normal;
padding-right:10px;
}

alt131

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4314025 posted 3:36 pm on May 25, 2011 (gmt 0)

Thanks for that VuoriLiikaluoma,

OK, we need to stop moving the goal posts and get this working, so I suggest you identify exactly what you are trying to achieve, and how you plan to go about it. This will be a long post, but I'm not sending you "back to the drawing board" - more like clearing the drawing board so we can see what's on offer :)

To me this looks like a simple form, images and text, with the elements able to scale. Not too difficult, but the code looks designed to micro-control the elements. If your goal is flexibility that means the code is not helping you achieve the desired layout.

Keep in mind that css styles HTML elements - and HTML elements reflect the content. So start by controlling the HTML so it helps rather than getting in the way. I performed the following exercise and achieved the same output as your original, but using just one classed container div, the form with just only, one span and one <b>. A dozen elements, and only one class - so much easier to manage!

  1. Ask if each element is required. Most of the divs and spans could be removed. For example, the unclassed div, .prod_image, div. center_block. It isn't necessary to divide the document at those points, divs are generic elements so don't add any meaning to the document, and they are not required for styles. They don't have any purpose, so remove them.
  2. When using elements, choose ones that already have meaning and are as small as possible - as illustrated in the above example. For example, span.price has been used to bold text - what is wanted is a <b> with styles for font-size. Avoids a class, and less to type ;)
  3. When doing that, avoid setting styles inline as they become hard to trace, plus save time by not setting defaults. For example, span.price has been styled display:inline, but a span is inline by default. Delete!
  4. Usually it is more efficient to set styles on the container, but in your case it creates a circle of setting them, then "undoing" them on child elements. In this case I;d suggest be more specific. For example, all the inputs are bold, so style them so. Another example is div.right_block, which has been used to set font-sizes - but both child elements have font-sizes as well. More efficient to remove the div and adjust the font-sizes on the children only.

Next step is to decide how to lay the form out. Either of the above examples could be used, although I'd suggest replacing the suggested divs with a more meaningful element. or drop the form into the list similar to the example I gave.

Now you can see what you're looking at you can deal with the issue that started this.

The big hurdle here is the lack of dimensions. Elements needs a size if we want to change the default layout (flow). And really necessary given you want unrelated images plus unrelated text to be drawn so they seem to have been aligned.

Dimensions will also avoid the "jumps" commonly seen on product pages: This is caused by unsized elements being drawn, then the browser having to redraw the elements as the image comes down - so the text appears to "jump" to the new position. Unsightly, difficult for users and quite avoidable.

So, can you identify the maximum height you are expecting the images to be? That will allow a container to be sized (using ems or %) so the text can be placed around it while retaining the ability to scale.

VuoriLiikaluoma



 
Msg#: 4314025 posted 9:25 am on May 26, 2011 (gmt 0)

The product images will be varying in size, there's no set maximum height. But I could set one if necessary.

Stripped the code down as much as I could...

Serverside:

{if !isset($i)}
{$i = 1}
{/if}
{if isset($products)}
<!-- Products list -->
{foreach from=$products item=product name=products}
<div class="product_block {cycle values="Block1,Block2,Block3"}">
<form action="{$product.link|escape:'htmlall':'UTF-8'}" method="post" accept-charset="utf-8" id="form{$i}">
<p>
<input type="hidden" name="products" value="{$products|serialize|base64_encode}" />
{if isset($prev)}<input type="hidden" name="previous" value="{$prev}" />
{elseif isset($previous)}<input type="hidden" name="previous" value="{$previous}" />{/if}
{if isset($categ_id)}<input type="hidden" name="categ_id" value="{$categ_id}" />{/if}
{if isset($search_query)}<input type="hidden" name="search_query" value="{$search_query}" />{/if}
<!--TODO: if new--><input type="image" src="{$img_dir}nyhet.png" class="NyhetImg" alt="{l s="Nyhet!"}"/><!--/if-->
<input type="image" src="{$link->getImageLink($product.link_rewrite, $product.id_image)}" class="ProdImg" alt="{$product.legend|escape:'htmlall':'UTF-8'}"/>
<input type="submit" value="{$product.name|truncate:35:'...'|escape:'htmlall':'UTF-8'}" alt="{$product.name|escape:'htmlall':'UTF-8'}" />
</p>
</form>
{if (isset($product.show_price) && $product.show_price)}<b>{if !$priceDisplay}{convertPrice price=$product.price}{else}{convertPrice price=$product.price_tax_exc}{/if}</b>{/if}
</div>
{$i = $i + 1}
{/foreach}
{/if}


HTML

<div class="product_block Block1">
<form action="http://example.com/product.php?id_product=2" method="post" accept-charset="utf-8" id="form1">
<p>
<input type="hidden" name="products" value="blah..." />
<input type="hidden" name="previous" value="category" />
<input type="hidden" name="categ_id" value="9" />
<!--TODO: if new--><input type="image" src="http://81.224.195.198/themes/moblera/img/nyhet.png" class="NyhetImg" alt="Nyhet!"/><!--/if-->
<input type="image" src="http://81.224.195.198/img/p/2-46.jpg" class="ProdImg" alt="iPod shuffle"/>
<input type="submit" value="iPod shuffle" alt="iPod shuffle" />
</p>
</form>
<b>42,57 kr</b></div>


CSS:

#Blocks input.NyhetImg
{
position:absolute;
}

#Blocks input.ProdImg
{
width:100%;
}

#Blocks div.product_block
{
width:24%;
display:inline-block;
vertical-align:top;
padding:3% 0;
font-size:0.95em;
text-align:right;
}

#Blocks div.product_block form
{
text-align:left;
}

#Blocks div.Block1, #Blocks div.Block3
{
margin:0 6%;
}

#Blocks div.product_block input
{
background-color:transparent;
border:none;
color:inherit;
cursor:pointer;
display:inline;
font-size:0.90em;
font-weight:bold;
margin-bottom:5px;
padding:0;
}

[edited by: engine at 9:51 am (utc) on May 30, 2011]
[edit reason] examplified [/edit]

alt131

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4314025 posted 1:15 pm on May 26, 2011 (gmt 0)

Good job on the code. With min/max heights this becomes easy:
  1. Take your existing HTML and remove the <p>.
  2. Wrap a <fieldset> around all the inputs except the last (value="iPod shuffle") and enclose that in a confirming element.
  3. In the css make a new rule:
    fieldset {
    height: <-- maximum height of any image
    border:none<--- removes default border
    }
  4. In the css adjust
    div.product_block {
    width:24%;
    /*display:inline-block; unless only supporting new browsers, this is less efficient that float*/
    float:left;
    /*vertical-align:top; no longer required*/
    padding:3% 0;
    font-size:0.95em;
    text-align:right;
    margin: 0 3% 1%; /* adds a bottom margin for clearance between rows*/
    }

  5. Add a max height for images:
    input.ProdImg {
    width:100%;
    max-height: <-- maximum height of any image
    }

  6. For older ie add
    <!--[if lte IE 7 ]>
    <style type="text/css">
    fieldset {height: <--- ie6 doesn't understand min-height, so needs a height, and needs to be larger than the height set above)
    input.ProdImg {max-height: <--- ie7 needs a larger height }
    </style>
    <![endif]-->

kb5nju

5+ Year Member



 
Msg#: 4314025 posted 9:20 pm on May 26, 2011 (gmt 0)

Hey alt131 - Thanks for this great lesson in CSS.

alt131

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4314025 posted 10:19 am on May 27, 2011 (gmt 0)

Hi kb5nju, how lovely to take the time to say such a nice thing!

Also note that at #2 above I said "confirming element". That should have been conforming element.

What I really enjoyed was how much this highlights the relationship between css and the html elements being styled: Once we saw the actual code it seemed easiest to use an html structure similar to your solution ... but not inline-block which both of us suggested :)

[edit]Spelling!

VuoriLiikaluoma



 
Msg#: 4314025 posted 9:32 am on May 30, 2011 (gmt 0)

Thanks for the replies alt131. I tried something like that while waiting for you to answer a post or two back... Anyhow, I tried out the code and while it's working nicely it doesn't scale. For example, if I set the height to 200px which looks good on 1920x1080 it causes lower resolutions to have an excess of white-space between the image and text. Also on higher resolutions (or zoomed out) it squashes the images. Not very nice... Tried using percentage but that would require putting percentage on a parent elements as well and I'm not sure how that would work... Will try it though...

In case your wondering about the p tag (didn't think about using fieldset), that was there for conformance with XHTML 1.1, according to which input tags aren't allowed in form but need a ins, del, h1-6, p, div, address or fieldset element parent. Seems to me you didn't take that into account...

Also I disagree about float:left; vs. display:inline-block;. Older versions of Firefox have problems with float which are easily fixed by using display:inline-block; instead. And display:inline-block; is easier to control than float. Also for support on older IE versions I use display:inline; zoom:1; on the elements with display:inline-block;. The IE CSS is added through an IE conditional comment like the one you suggested except I have a link element in it. IE 6 and 7 will for some random reason maintain the block status of an element even with display:inline;. And zoom:1; causes IE 7's hasLayout to become activated and magically make things work nicely.



In case you care; the actual minimum browser version support requirements for the site are:
IExplorer: 6
Firefox: 3.5
Opera: 11.1
Safari: 5
Chrome: 11 (Though chrome is also webkit-based like safari, it's Googleized and weird.)

Basically only Firefox and IE users are lame enough to not upgrade their browsers as can be seen on various browsers usage statistics sites. Old IE's on older OS's is understandable though, but to use them instead of say Firefox or Opera that work on older OS's as well is beyond me. Also older chrome versions are also still in use, though the user base of old chrome versions is not high enough to worry about.

[edited by: engine at 10:12 am (utc) on Jun 1, 2011]

lucy24

WebmasterWorld Senior Member lucy24 us a WebmasterWorld Top Contributor of All Time Top Contributors Of The Month



 
Msg#: 4314025 posted 11:05 am on May 30, 2011 (gmt 0)

Ooh, that post just cries out for a "When you get to be our age..." response. Who's the Official Greybeard hereabouts?

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / CSS
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved