1

So I'm trying to underline the <a> elements of my header. The problem, I believe, is that for some reason jQuery isn't getting the proper width of the <a> text, as it's in an embedded font.

UPDATE: Oddly, this is only occurring within Chrome and Safari, so Webkit browsers are having this issue.

Here's the relevant CSS:

* 
{
  padding: 0;
  border: 0;
  margin: 0;

}

a 
{
  text-decoration: none;
  color: inherit;
  cursor: pointer; 
}

body 
{
  height: 100%;
  margin: 0;
  padding: 0;
}
body > #container 
{
  min-height: 100%;
  position: relative;
  height: 100%; 
}
body > #container > header 
{
  width: 100%;
  background-color: black;
  color: white;
}
body > #container > header > #title 
{
  font-family: 'Shadows Into Light', cursive;
  padding: 12px 0px 12px 30px;
  font-size: 42px;
}
body > #container > header > #title > .navigation 
{
  font-family: 'Montserrat', sans-serif;
  float: right;
  display: inline; 
}
body > #container > header > #title > .navigation > span 
{
  display: block;
  float: left;
  text-decoration: none;
  font-size: 20px;
  padding-left: 20px;
  padding-right: 20px;
  padding-top: 20px;
}
body > #container > header > #title > .navigation > #magic-line 
{
  position: absolute;
  padding-top: 5px;
  top: 60px;
  left: 0;
  background: white; 
  padding-left: 0px;
  padding-right:0px;
}
body > #container footer 
{
  color: #3e606f;
  text-align: center;
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 40px; 
}

Here's my header.html

<!DOCTYPE html>
<html>
<head>
    <link href="css/header.css" media="screen" rel="stylesheet" type="text/css" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
    <script src="js/header.js"></script>
    <link href='http://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Shadows+Into+Light' rel='stylesheet' type='text/css'>
    <meta property="og:image" content="res/BigduckSe.png" />
</head>
<body>
    <div id="container">
        <header>
            <div id="title">R.A.G.E.
                <span class = "navigation">
                    <span class="current_page_item" id="home">
                        <a href="index.html">HOME</a>
                    </span>
                    <span id="about">
                        <a href="videos.html">ABOUT</a>
                    </span>
                    <span id="points">
                        <a href="#">POINTS</a>
                    </span>
                    <span id="schedule">
                        <a href="#">SCHEDULE</a>
                    </span>
                    <span id="swag">
                        <a href="#">SWAG</a>
                    </span>
                </span>
            </div>
        </header>
    </div>
</body>

And here's the all-important header.js

var ready1 = function() {
    var $el, leftPos, newWidth,
        $mainNav = $(".navigation");

    if($("#magic-line").length){

    }
    else{
        $mainNav.append("<span id='magic-line'></span>");
    }

    var $magicLine = $("#magic-line");

    $magicLine
        .width($(".navigation .current_page_item a").width())
        .css("left", $(".current_page_item a").position().left)
        .data("origLeft", $magicLine.position().left)
        .data("origWidth", $magicLine.width());

    $(".navigation span").hover(function() {
        $el = $(this);
        leftPos = $el.children("a").position().left;
        newWidth = $el.children("a").width();
        $magicLine.stop().animate({
            left: leftPos,
            width: newWidth
        },200);
    }, function() {
        $magicLine.stop().animate({
            left: $magicLine.data("origLeft"),
            width: $magicLine.data("origWidth")
        },200);
    });
};

var resizeWindow = function() {
    //adjusting the body size dynamically
    var $headerfooter=$("header").height()+$("footer").height();
    var $bodyheight=$(window).height()-$headerfooter;
    $(".body").css("height",$bodyheight);


    //adjusting position of wrapper dynamically
    $("#wrapper").css("top",(.1*$bodyheight));
    var $wrapperheight = .8*$bodyheight;
    $("#wrapper").css("height",$wrapperheight);
};

$(window).load(ready1);


$(window).resize(ready1);
$(window).resize(resizeWindow);

I would put all of this on jsfiddle, but for some reason when I do, it formats properly. This only seems to happen when testing on an actual browser. In addition, you can see I'm using the window.load instead of document.ready, as I've read that could be the cause of the incorrect width, but it's not helping at all.

Also note, the second I resize the window, the underline properly works.

If anyone could help, it would be greatly appreciated.

mike10010100
  • 163
  • 8

2 Answers2

0

The window resize event and also the DOM ready event are called earlier then the Google Font is loaded. My solution is to use the Web Font Loader to get control about the moment the Google Font is loaded... "It is co-developed by Google and Typekit."

First, it is described here: https://github.com/typekit/webfontloader

Just an approach:

var activeCallback = jQuery.Callbacks(); // define a callback

activeCallback.add(function() { // add a callback function
    resizeWindow();
});

WebFont.load({
    google: {
        families: ['Montserrat']
    },
    active: function () { activeCallback.fire(); } // fire the callback
});
algorhythm
  • 8,530
  • 3
  • 35
  • 47
  • Is there a way to do it without yet another plugin? Or is it unavoidable? – mike10010100 Oct 28 '14 at 21:15
  • To my knowledge that's the best solution... The Web Font Loader loads the font and no longer your `` tag. That's the reason why you can know the time when this happens. Have also a look at here: http://stackoverflow.com/questions/11941883/call-jquery-function-after-fonts-are-loaded The problem is, that there is no event the is called, if the `` tag is completely loaded. – algorhythm Oct 28 '14 at 21:22
  • You could try to dynamically add the `` tag to head like this `$('head').append('');` and after it call your function. But in your current solution and also in this hint you have to do a small sleep to wait a bit for loading the resource. And you will never exactly know how long you have to wait. If the internet connection is slow or the server the resource is coming from, then your sleep time could be to less... – algorhythm Oct 28 '14 at 21:32
  • I believe I found a much simpler solution. Check my response. – mike10010100 Oct 28 '14 at 21:37
0

Turns out there's a way around this. Keeping the window.load as the method by which to call the function (document.load, again, fails to properly contain the font), simply import the font via a script tag in the head:

<script type="text/javascript">
        WebFontConfig = {
            google: { families: [ 'Montserrat::latin' ] }
        };
        (function() {
            var wf = document.createElement('script');
            wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
            '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
            wf.type = 'text/javascript';
            wf.async = 'true';
            var s = document.getElementsByTagName('script')[0];
            s.parentNode.insertBefore(wf, s);
        })(); 
    </script>

This seems to force the font to load before the rest of the page renders, and thus has it ready in time for the window.load function. Now my text width is properly calibrated.

BUT (and here's the important bit, it would seem), DO NOT REMOVE THE <link href='http://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'> I'm not sure why, but this messes up the formatting again.

mike10010100
  • 163
  • 8
  • But you also need the Web Font Loader, isn't it? – algorhythm Oct 28 '14 at 22:21
  • Not AFAIK, I didn't do anything except insert this into the head of my HTML. Really strange, but it works. – mike10010100 Oct 28 '14 at 22:29
  • Yeah, maybe. Couldn't explain it actually. But the fact is, that your solution already loads the Font Loader and then the solution to react an `WebFont.load` is probably a bit better and even faster than to dynamically load a JavaScript like that. It's the same thing when you use `@import` in CSS files... First the browser loads your above script. And after it makes a new connection to the server to get the second script namely the `webfont.js`. The same with the `@import` in CSS. First it loads the CSS containing the `@import` and after the CSS that should be imported. – algorhythm Oct 28 '14 at 22:39