Styling HTML links and buttons in order to appear the same

When creating the game menus using HTML and CSS, there are 2 elements that can be used to interact with the user, that are links, using the <a> HTML tag, and buttons, using the <button> HTML tag.

Each of these 2 elements has its optimal use case, and they can be made to appear the same using some CSS.

Let's start talking about links, that are one of the most used HTML elements. A link is a simple <a> tag like this:

<a href="#menu_item_value" class="menu-item">Menu Item Content</a>

The first thing to notice is that the href part of the link starts with the symbol #, which means that the link refers to an internal target location within the current document (an id).

Doing so will not trigger a page reload when clicked, which would have reset all the game state.

In the context of game menus, the part after the # sign is the part that identifies the menu item, and does not have to refer to an actual id inside the page.

After the link has been clicked, the location.hash gets replaced with the menu item identifier, and it will persist page reloads, so this element is useful to maintain menu state information and user choices, especially when using LiveReload or similar tools.

The other element is the <button> element, used like this:

<button type="button" value="menu_item_value" class="menu-item">Menu Item Content</button>

Here the menu item identifier is the value attribute of the element, and when the button is clicked, the location.hash remains the same, so a page reload will lose the menu state. On the other hand, this is more semantically correct than using a link for a menu item, and it does not change the text in the URL bar of the browser.

The class attribute is defined in both cases, in order to ease styling and event handling, and in both cases the menu item can contain any HTML element, not just simple text.

Now that we have seen the difference between a button and a link, let's give them an unified look, in order to use them interchangeably.

Here's the CSS needed to reset the style of both elements:

.menu-item {
    /* Buttons are displayed inline-block, while links are displayed inline */
    display: inline-block;
    vertical-align: middle;

    /*
    Buttons have some padding, here we reset it, but it is something that
    can be redefined in the custom menu element style
    */
    padding: 0;

    /* Links have a pointer cursor, while buttons have a normal cursor */
    cursor: pointer;

    /* The text of buttons can't be selected */
    user-select: none;

    /*
    Buttons have a background and a border, while links don't
    Notice that usually game menu elements have a background
    and a border, so they will be redefined in the custom menu
    element style
    */
    background: none;
    border: none;

    /* Buttons don't have an outline when clicked */
    outline: none;

    /*
    Links use different colors than normal text, and buttons use
    a different font than the rest of the page.
    Notice that along with background and border, the font and
    text color will also be changed by the custom menu element style
    */
    font: normal normal 100% sans-serif;
    color: black;

    /*
    Buttons have centered text with no decoration, while links have
    left aligned text with underline
    */
    text-align: center;
    text-decoration: none;
}

This makes the links and buttons appear almost the same, however there are still a couple of issues:

On Firefox, the button still has some padding, and it will still have an outline when clicked, even after we set the corresponding properties in the CSS.

This is due to Firefox adding a pseudo class named ::-moz-focus-inner to the button element, so that must be styled as well. Also, on older Firefox versions it was impossible to change the line-height property of buttons, so we might set it to the Firefox default as well, in order to have a consistent line-height when using links.

.menu-item {
    /* Required for older versions of Firefox */
    line-height: normal;
}

/*
Required to remove the dotted outline and the
remaining padding on buttons on Firefox
*/
.menu-item::-moz-focus-inner {
    border: 0;
    padding: 0;
}

Ok, now the elements are normalized, and I can apply my custom style, right?

Wrong, if you play with the padding, width, and height properties you will still notice something strange: why on Earth the link is bigger than the button if I have explicitly specified the width and height of the element?

The answer lies in what the browser interprets as width and height of an element, but basically we can fix it by setting the box-sizing property. Paul Irish wrote an excellent article on this subject.

.menu-item {
    /* Fix inconsistencies of width and height */
    box-sizing: border-box;
}

One last inconsistency is that on buttons the text is vertically centered, so we can apply this style in order to vertically center the text regardless if the element is a button or a link:

.menu-item:before {
    content: '';
    display: inline-block;
    vertical-align: middle;
    height: 100%;
}

For an explanation of why this works, see this blog post.

Finally we have reached our goal, now we can apply our custom style, and both elements will look the same.

In order to apply the custom style, there are 3 pseudo-classes worth mentioning:

  • :hover activated at element mouse over
  • :active activated when the element gets clicked
  • :focus activated when the element receives focus, either after the click, or when selected with the TAB key

So the CSS will have the custom style without the pseudo classes as the style for the element in the normal state, and a style for the various states, that has only the properties that change compared to the normal state. As usual, it is possible to define the same style for multiple states like this:

/* Custom style for normal state */
.menu-item {
    padding: 20px;
    border: 1px solid black;
    background: yellow;
}

/* hover and focus will have the same style */
.menu-item:hover, .menu-item:focus {
    background: lightgreen;
}

.menu-item:active {
    background: darkgreen;
}

A couple of notes before ending the discussion about the CSS:

Some of the properties used in the examples in this page are relatively new, so some older browsers may support them by using a non-standard browser-specific prefix. In order to support those browsers without having to type the prefix for each browser, a CSS framework like Compass or similar is recommended.

Finally, this CSS reset has been done assuming the browser default style as a starting point. If you use a CSS framework like Twitter Bootstrap or similar, some more normalization work might be needed, depending on how much the CSS framework customizes the <a> and <button> elements.

Now that we have seen how to style these elements, let's see how to handle click events, and get the value of the clicked element in both cases using jQuery.

As far as the links are concerned, they can be handled with a function like this:

$('.menu-item').click(function () {
    var
        // Get only the part after the '#' symbol
        item_value = $(this).attr('href').split('#')[1]
    ;
});

Notice that some extra string processing is needed in order to get rid of the # symbol.

Regarding the buttons, the code for getting the value is much simpler:

$('.menu-item').click(function () {
    var
        item_value = $(this).val()
    ;
});

Ok, that's all for now as far as the web technologies are concerned, the next blog post will return to address more game development specific topics, stay tuned.

Comments !