0

I have a line of text as follow:

->A B C D E F G H I J                   <-

I want to position the line of text using CSS such that letter D is at the centre of the page as shown below:

->             A B C D E F G H I J      <-

Any idea?

Question Overflow
  • 10,925
  • 18
  • 72
  • 110
  • 1
    Javascript, and even then you'll need to wrap each letter in an element. – David Thomas Mar 11 '12 at 10:27
  • @DavidThomas: That would be complicated, wouldn't it? – Question Overflow Mar 11 '12 at 10:31
  • @BenHuh Yep, but it can't be done in simple CSS. Once upon a time, there were the `char` and `charoffs` attributes, but they were hardly supported by most browsers. Anyway, if you tell us a bit more about the context here, maybe we can come up with something elegant. – Mr Lister Mar 11 '12 at 11:00
  • @MrLister: thanks for your interest in this. Actually it is a page navigational bar that I want to create, with the current page number positioned at the centre and links to adjacent pages dynamically generated to the left or right of the current page. – Question Overflow Mar 11 '12 at 11:07

4 Answers4

3

If you use a monospaced font then you can use position:relative; and move your row of text, since every letter and space has the same size (demo). You can achieve a similar result on fonts without fixed-width, but the offset (left:;) is a little bit harder to calculate, as almost every letter occupies another amount of horizontal space.

<nav class="letter monospace">
    <div>A B C D E F G H I J</div> <!-- monospaced font demo -->
</nav>
<nav class="letter">
    <div>A B C D E F G H I J</div> <!-- standard browser font demo -->
</nav>
<div id="leftmiddle"> </div>
<div id="rightmiddle"> </div>
nav.letter{
    font-size:2em;
    text-align:center;
}
nav.letter > div{ /* standard browser font */
    position:relative;
    left:1.05em; /* you have to calculate the horizontal shift yourself based on the font you're using */
}
nav.letter.monospace{
    font-family:monospace;
}
nav.letter.monospace > div{ /* monospaced font */
    position:relative;
    left:1.75em; /* to center the row around 'E' change to 0.75em, for C to 2.75em... */
}

nav ~ div{
    width:49%;
    min-height:200px;
    height: 80%;    
}
#leftmiddle{ float:left;    border-right:1px solid;}
#rightmiddle{    float:right;    border-left:1px solid;}

HTML4 demo, working in IE7-9, FF10, Opera, Chrome.

UPDATE: See this alternative demo (working in IE7-9, FF10, Opera, Chrome):

<div class="letter">
    <div class="wrapper">
        <div class="before">
            A B C
        </div>
        D       
        <div class="after">
            E F G H I J
        </div>
    </div>
</div>
.letter{
    text-align:center;
    overflow:hidden;
}
.letter > .wrapper{
    width:1em;
    margin:auto;
    position:relative;
}
.letter > .wrapper > .before{
    position:absolute;
    right:125%;
    text-align:right;
    width:10em;
}
.letter > .wrapper > .after{
    position:absolute;
    text-align:left;
    top:0;
    left:125%;
    width:20em;
}
Zeta
  • 103,620
  • 13
  • 194
  • 236
1

Maybe use something like

<div id="container" style="position: absolute; width:1000px; height:10px">
    <div id="innerContainer" style="position: absolute">
        <span>A</span><span>B</span><span>C</span><span>D</span><span>E</span><span>F</span>
    </div>
</div>

and then something like the following in JQuery in $(document).ready() {}

var left_pad = 20; // set this to container width / 2
                   // calculate it or hard code it
$("#innerContainer").css("left"),$((left_pad - span:contains('D').position().left) + 'px')

just off the top of my head, no time to test, but hope it points you in the right direction. With a bit of patience this should be able to be gotten working.

Sparklellama
  • 712
  • 1
  • 6
  • 18
  • Yes, possibly a solution, but still requires jquery. I am thinking along the line of using margins and negative margins. Let me try out first. Thanks. – Question Overflow Mar 11 '12 at 11:09
1

As @DavidThomas pointed out, JavaScript is required. I just wanted to expand on this a bit.

CSS cannot achieve this for a couple main reasons:

  1. There's no way to know how to alter the line of text in question so that D is centered until the document flow has been established. But the application of CSS is central to document flow, so at the time that CSS is being applied it can't possibly know what the final, resulting document will be. In other words, we'd have a catch 22 on our hands if CSS could be used for this. In order to "know" how to position that line of text, the page's CSS would already need to know what the final document would look like. But in order to get the final document, the CSS first needs to be applied.
  2. Even if 1 & 2 weren't the case, CSS still has no way of analyzing a page, grabbing the position of elements, etc. This simply isn't its purpose.

In contrast, JavaScript can be used to solve this issue because:

  1. Unlike CSS, JavaScript can do its work after the document flow has been established.
  2. JavaScript has the necessary tools for analyzing the page so that it can make the necessary changes.

Hard to say how complicated it would be to achieve with JavaScript without knowing more about your specific case. If you know JavaScript, however, I think it would be fairly simple.

maxedison
  • 17,243
  • 14
  • 67
  • 114
1

This is posted for two simple reasons:

  1. I commented and said that you'd need to use JavaScript, and
  2. Sometimes, I just can't help myself...

That said, here's a plain JavaScript solution that does not require any library. It's somewhat cumbersome, and I feel that there must be ways in which it can be simplified, however:

// helper function, to save typing later on.
function gEBTN(tag, parent, index) {
    if (!parent && !index) {
        return document.getElementsByTagName(tag);
    }
    else if (parent && !index) {
        return parent.getElementsByTagName(tag);
    }
    else if (index) {
        return parent.getElementsByTagName(tag)[index];
    }
}

// helper function, to save typing later on.
function gCS(elem, parent, prop) {
    if (!prop && parent) {
        return window.getComputedStyle(elem.parentNode, null).getPropertyValue('width');
    }
    else if (prop && parent == true) {
        return window.getComputedStyle(elem.parentNode, null).getPropertyValue(prop);
    }
    else if (!parent && !prop) {
        return window.getComputedStyle(elem, null).getPropertyValue('width');
    }
    else {
        return window.getComputedStyle(elem, null).getPropertyValue(prop);
    }
}

// page: number.
// navElemId: a quoted string, the Id of the element containing
//            the navigation elements, defaults to 'navigation'
// container: a quoted string, the type of element ('div','span','li'...)
//            that forms the navigation 'buttons.' Defaults to 'li.'
function centreNavigationOn(page, navElemId, container) {
    if (!page) { // at minimum you have to supply the page you want to centre on
        return false;
    }
    else {
        var navElemId = navElemId || 'navigation';
        var navElem = document.getElementById(navElemId);
        var containers = gEBTN(container) || gEBTN('li', navElem);
        for (var i = 0, len = containers.length; i < len; i++) {
            if (containers[i].innerHTML == page) {
                var centreOn = containers[i];
            }
            else {
                // just for an easy visual difference between the centred/current
                // page and the others. Adjust/remove according to taste
                containers[i].style.opacity = '0.3';
            }
        }
        if (!centreOn){
            // if no page is found to be centred on, quits
            console.log('No element found to centre on. Quitting now.');
            return false;
        }

        // again, just for simple visual difference between current and others...
        centreOn.style.backgroundColor = '#f90';
        centreOn.style.opacity = '1';

        // finds the width of the centreOn element
        var cOnWidth = parseInt(gCS(centreOn),10);
        var cOnLeftOffset = centreOn.offsetLeft;

        // the centreOn element's parent's parent's width
        // this made sense when I wrote it, now...I'm not so sure... =/
        cPPWidth = parseInt(gCS(centreOn.parentNode.parentNode),10);

        // works out by what distance the centreOn element's parent
        // must be moved in order to centre the centreOn element within the page.
        var moveBy = Math.round((cPPWidth/2) - (cOnLeftOffset + (cOnWidth/2)));
        centreOn.parentNode.style.marginLeft = moveBy + 'px';
    }
};

centreNavigationOn(4, 'navigation', 'li');​

JS Fiddle demo.

Notes: this function will fail in those browsers, such as IE, that have no implementation of window.getComputedStyle(). This probably guarantees that, as interesting as it was to put together, this script is unlikely to be used. Except, perhaps, in a modified form (I do, of course, freely give this script to anyone who wants to use it, releasing it even beyond the CC-By-SA license of Stack Overflow, as I think I'm able...). Though if anyone does modify it, I'd genuinely appreciate their linking to the modified version, either in comments or by editing this answer to add links...

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410