Need help centering a banner...

Discussion in 'CSS' started by rmkreeg, Aug 16, 2009.

  1. #1
    I'm new to hand coding XHTML. Go easy on me.

    While learning XHTML I'm building a small sample site for fun. I already have CSS set up for a single centered background image that I'm hoping will visually frame my content:
    body
    {
    background-image: url("background.jpg");
    background-repeat: no-repeat;
    background-position: top center;
    background-color: #55616F;
    color: #F5BA5c;
    }
    Code (markup):
    This obviously will be a general look for the entire site. Now, on one particular page I have a banner that I want to line the top of the page (non-informational and purely for looks). I want the banner to be centered and line up perfectly with the background image no matter what size the end-user sizes their browser. I've tried something along these lines:
    div.centered
    {
    margin-left:auto;
    margin-right:auto;
    text-align:center;
    }
    
    <div class="centered"><img src="banner.png"/></div>
    Code (markup):
    And this mostly works so long as the size of the browser windows doesn't get smaller than the width of the banner. When the window gets smaller than the banner, then the left side of the banner butts up against the left edge of the window and gets pushed off-center from the background image. Again, I want the center of the banner to match the center of the background image at all times so that when the window gets smaller than the width of the banner, the banner should clip on both the left and right sides.

    I really don't know where to go from here since my XHTML vocabulary is small right now. Oh yeah, FYI, I'm trying to be a strict and kosher as possible with my code.

    Is there maybe a way to do layered background images?
     
    rmkreeg, Aug 16, 2009 IP
  2. Rasczak

    Rasczak Peon

    Messages:
    131
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    0
    #2
    If you want to center an element, you have to specify its width. By default, a DIV has 100% width, so the margin: 0 auto is obsolete.
     
    Rasczak, Aug 16, 2009 IP
  3. rmkreeg

    rmkreeg Member

    Messages:
    13
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    36
    #3
    So this sort of a hack:
    div.centeredimage
    {
    margin-left:auto;
    margin-right:auto;
    margin-top:0px;
    margin-bottom:0px;
    padding:0px;
    width: 0px;
    position:relative;
    left:-500px;   /* move the div half the width of the banner to the left. in this case the banner is 1000px wide */
    }
    
    
    <div class="centeredimage">
    <img src="images/why/banner.png"/>
    </div>
    Code (markup):
    What this effectively does is sets the left edge of the div to the center of the screen and then offsets the origin to the left. This gives me exactly the behavior I was looking for....now will it be compatible in browsers other than Chrome? I have no clue...
     
    rmkreeg, Aug 16, 2009 IP
  4. Stomme poes

    Stomme poes Peon

    Messages:
    3,195
    Likes Received:
    136
    Best Answers:
    0
    Trophy Points:
    0
    #4
    
    body
    {
    background-image: url("background.jpg");
    background-repeat: no-repeat;
    background-position: top center;
    background-color: #55616F;
    color: #F5BA5c;
    }
    
    Code (markup):
    can be

    
    body {
      color: #f5ba5c;
      background: #55616f url(background.jpg) top center no-repeat;
    }
    
    Code (markup):
    The less code there is, the easier it is to read, in my opinion. You may need to get comfortable with CSS shorthands first. Background is easy because it's forgiving. Font shorthands on the other hand have stricter rules in who you can use and who you can leave out.

    This:
    
    div.centered
    {
    margin-left:auto;
    margin-right:auto;
    text-align:center;
    }
    
    <div class="centered"><img src="banner.png"/></div>
    
    Code (markup):
    Could have been this:
    
    .banner {
      display: block; 
      margin: 0 auto;
    }
    <img class="banner" src="banner.png"  width="something" height="something" alt="TEXT BABY" />
    
    Code (markup):
    *Although this is assuming there's a page-wrapping div within the body, since the body needs a block child, and images are inlines. If not, then you would need the div, to remain valid in your code.*

    Note: it's always a good idea to have width and height attributes in the image tag, unless you don't know the dimensions. This is not considered mixing presentation with content, because the img tag is empty and calling a real file with real dimensions, and you are simply telling the browser as early as possible how much room to reserve for it.
    The alt="" is required (your code will not be valid without it), whether the image is actually saying/meaning anything or not. If your image is ever truly content (in this case, you're just playing around with decoration) your alt text needs to tell those who can't see images what they're missing.

    If you're going to use XHTML syntax, make sure you don't get any dodgy old browsers worked up; put a space before the closing slash on the empty elements like img (like I did above). XHTML follows the rules of XML, which requires all tags closed, but browsers don't parse it like XML, because you're not sending it as XML. You're sending HTML dressed up as XHTML, and while most newer browsers know to ignore that closing slash, older browsers considered it an error (because for HTML it is an error) and puke on it. The space magically fixes that. : ) so it's <img /> not <img/> in practice.

    The auto-margin centering only works on blocks (a div is already a block) who have widths (like Rasczak said). If you're 100% wide, you can't be centered, naturally. In your code, the inline child (the image) of the block div was centered with the text-align: center. You could have used auto-margins to center the div if you'd stated its width as being the same as the image it holds (CSS works with There's More Than One Way To Do It, or "Tim Toady". However that can mean many bad ways and one or two good ways).

    In my example code, I didn't set a width on the image because images are those rare special inlines who call a file who already has a set width (though instead of relying on the browser to check, I state the width in the HTML on images), and most browsers can just use that instead. But first I had to make the image a block, because inlines can't be centered with automargins. Instead, to center an inline, its container needs to hold text-align: center (so you can't get away with putting text-align: center on the image itself):
    <img src="blah" alt="" />
    img {
    text-align: center;
    }
    does nothing!
    But

    <someblock><img src="blah" alt="" /></someblock>

    someblock {
    text-align: center;
    }
    this will center its inline children, here the img.




    In a left to right page (like we Engrish-spreakrs have), content (anything in the HTML) wants to not go offscreen on the left or the top (because imagine how annoying that would be!). This is why your banner stayed centered until the browser was too small.

    The background of the body won't do this because it's not content. It's a background.

    You've found one solution, which was to take the banner out of the document flow partially and position it like that. But, I don't think you can see what you actually did.

    Since you've set the width to 0px, what you're seeing with the image is overflowing out of the container. Here's another way you'll occasionally see that's very similar:
    
    img.banner {
      position:relative;
      left: 50%;   /* start the left side of the banner half-way across its own width  */
      margin-left: -500px; /*pull the left side back by half its width to make it look centered*/
    }
    
    <img class="banner" src="images/why/banner.png" width="1000" height="whatever" alt="teh bannerz, ze do nossing!" />
    
    Code (markup):

    However in a real-life page, if this banner was not an ad or something to be clicked, not any kind of content but just decoration (what reason would you have making content go off-screen where it's not reachable by scrollbar??) what most of us would do is make a full-page container (something that wraps everyone who's inside the body) and put the banner as a background image just like you did with the body. Giving it a top padding makes sure the next element to come doesn't cover it:
    
    <body>
    <div id="page">
    <the rest of the page/>
    </div>
    </body>
    
    body {
      color: #f5ba5c;
      background: #55616f url(background.jpg) top center no-repeat;
    }
    #page {
      padding-top: 200px; /* assuming the image was 200px tall */
      background: url(theimage.xxx) top center no-repeat;
    }
    
    ...
    
    Code (markup):
    This would work better, and would match the body's background and do what the body's background image does: not pay attention to the edges of the browser window.

    Since multiple backgrounds per element are so far only supported by Safari, this is pretty much how we do it. HTML elements who exist solely to hold background images are called sandbags, though generally you want to try to have as few of them as possible, or try to use pre-existing content to sandbag for you.

    You can either have empty boxes as sandbags <div></div> or you can have multiple wrappers which go all the way around the other content. Naturally every static block will stretch to 100% width, so their widths will line up perfectly. Heights are determined by content, so if the content inside the wrapper isn't tall enough to show all of the background image, you can set a min-height on the wrapper to ensure it shows:
    <wrap1>
    <wrap2>
    <content stuff needed 3 background and holds one />
    </wrap2> held another background
    </wrap1> held a 300px high background image

    wrap1 {
    min-height: 300px;
    }
    wrap 2 and the content inside still have auto height, based on the content inside's height, but wrap1 will always be at least 300px tall... min-height is safer here than just height since if the content inside grows, wrap1 won't cut anything off, but grows with the content like we usually want it to.
     
    Last edited: Aug 17, 2009
    Stomme poes, Aug 17, 2009 IP
  5. rmkreeg

    rmkreeg Member

    Messages:
    13
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    36
    #5
    Wow thank you very much for all the helpful info. It really explains a lot. It gets rather hard to learn anything without experienced people around.

    The idea of assigning the banner as a background in an element was exactly what I was looking for but I just couldn't wrap my head around how it could be done...so I reverted back to my game programming experience to make the zero width hack...which I still consider messy as its making the system do something it wasn't necessarily designed to do.

    Using the shorthands is something I've known about, but I've personally considered it less-readable syntax-wise. But that's a personal preference (again, previous programming experience coming into play). It will definitely be something I use when I get down to consolidating code to reduce file sizes.

    But again, I really appreciate your input. I brings me a little bit closer to understanding how the computer thinks when it comes to xhtml and css.

    Cheers!
    -Bob K
     
    rmkreeg, Aug 19, 2009 IP
  6. 1 FineLine

    1 FineLine Peon

    Messages:
    78
    Likes Received:
    2
    Best Answers:
    0
    Trophy Points:
    0
    #6
    Stome is the man. He explains everything in vivid detail. :)

    Shorthand is the way to go. It takes some getting used to to figure how to do it but once you get the jist of it it will become second nature.
     
    1 FineLine, Aug 19, 2009 IP
  7. Stomme poes

    Stomme poes Peon

    Messages:
    3,195
    Likes Received:
    136
    Best Answers:
    0
    Trophy Points:
    0
    #7
    I understand what you mean about coming from a programming background where it's better to list everything explicitly. When I look at HTML coded by a programmer, I can usually tell that's their background because they are more likely to have more divs, classes and id's than they need (often called divitis and classitis... yeah, HTML people never went to med school). In HTML and CSS, those rules are pretty much the other way around, unless you're using microformats.

    However the other rules of programming generally apply... well, except that golfing is a good thing I think... here we call it "minimal markup".

    Hmm, the Art and Alchemy of CSS seems to be just that... making things do stuff they weren't originally designed to do : ) The people who think these things up, we call geniuses. Stu Nicholls is one, Paul O'Brien is another. Using the overflow property to make containers enclose floats is an example of such alchemy.
     
    Last edited: Aug 20, 2009
    Stomme poes, Aug 20, 2009 IP
  8. wd_2k6

    wd_2k6 Peon

    Messages:
    1,740
    Likes Received:
    54
    Best Answers:
    0
    Trophy Points:
    0
    #8
    Hi, very informative post Poes, when you say

    Does this mean that anything which is a direct child of the body (not wrapped in anything) must be a block? why is this so?

    E.G

    
    <body>
    <img src="pic.jpg" />
    <div>Some Text</div>
    <span>Some Text</span>
    </body>
    
    Code (markup):
    Does this mean that the span and img are invalid in some way until they are wrapped in a block?


    Lastly when you say:

    So would you reccommend setting the dimensions within the (X)HTML for all images, and not inside the CSS?
    Would the same apply for SWF embeds then I guess..
     
    wd_2k6, Aug 20, 2009 IP
  9. Stomme poes

    Stomme poes Peon

    Messages:
    3,195
    Likes Received:
    136
    Best Answers:
    0
    Trophy Points:
    0
    #9
    Yes, but the error will only be caught by the validator if you're using a Strict doctype (I did not know this until recently). The specs say:
    The stuff in the () are what the element is allowed to hold. A block OR a script (and/or ins or del if they're in block context). Yeah, I thought it was stupid that they don't seem to say WHAT an element IS (like when I wanted to know if <address> could have <pre> in it ot vice versa... turned out I can't use them together in any combination) but it does state what an element can CONTAIN.

    Since I can't read the specs all that well, here's Tommy's nice explanation and he explains the <body> if you scroll down a ways.

    The other elements I can think of off the top of my head who must have block direct children (grandchildren can be anything) are FORMs, BLOCKQUOTEs and I'm pretty sure also the NOSCRIPT tag... common error in validation is a noscript with just an anchor or image inside it... needs a block like a p.

    Yup, at least in a Strict doctype. Again, someone said Transitional lets it go. Either way, the browsers usually don't have a problem whether it's valid or invalid, but of course you never know what a new browser will do with invalid code : )

    Yeah, and yes I also always set height and width on <object>s too, for the same reason. They're not tags with content (well, <object> can haz alternative content, so that one's a bit different) but they call a file instead.

    But here's where someone convinced me it was better to list the height and width in the HTML (CSS is fine, in fact you can use CSS to override the settings in the HTML if I remember correctly): http://www.iwdn.net/showthread.php?t=7205

    The exception to this for me is either:
    -when I'm being lazy : )
    -when I dunno the exact dimensions
    -when I'm doing a shtupid human trick, like having a ginormous image and then setting height and width to 100% and then stuffing the image into some sized block... you know, so the image grows if the text is enlarged and that makes the container grow? Neat trick. And there we're abusing the attributes for presentation, but whatever. : )
     
    Stomme poes, Aug 20, 2009 IP