📜 ⬆️ ⬇️

Practical CSS: a recipe for success

Below is the translation of the CSS note - A Recipe for Success , which deals with creating HTML / CSS tools in the browser of some sample menu. The article highlights some interesting cases and describes their solution in detail.

If you look at the standard restaurant menu (or recipe), there are the names of the dishes on the left, followed by a dotted line to the right edge, where the price of this dish is located. Let's look at Figure 1, to understand what is at stake.

1.
Picture 1
')
Although, at first glance, outwardly it does not seem difficult to repeat it using HTML, however, everything is not so simple, and you can stumble upon a sufficient number of pitfalls. But first things first!


Dotted lines



Since the structure is an unordered list, it is simply implemented using CSS (although you can give some arguments in favor of using a table in this case). But since in this article we focus on using CSS, we’ll use the list.

We have two major problems to overcome:

First, we need to place the text both on the left and on the right on the same line.

And secondly, we need to make the dotted line beginning strictly after the text on the left and ending strictly at the text on the right. It would be easy if the dotted line underlined the text, then we could set the styles for the lower border of the list item. However, our menu looks different, so you have to tinker a bit.

Left and right



First, let's deal with the positioning of the text. In order to arrange the price on the right, use the float property and set it either for the price itself or for the dish name, but then the price should be aligned with text-align: right . Or we can set a float for both parts of the list. Any of these methods will be correct, but in this case we will use the last method; setting the float for description in the left , and for the price - in the right .

To isolate one part of the text from another, we will have to resort to additional elements in our markup, in particular, we will use em for the text of the description and span for the price. This will allow access to them from list items directly, without adding additional classes. It is worth taking care of the cleanliness of your code and minimize markup: in some cases, it is worth adding another nested semantic element, and not an additional class to the existing one.

Below is a sample HTML for the list item:

 <ul>
      <li>
           <em> Some menu text </ em>
           <span> ÂŁ 9.99 </ span>
      </ li>
 </ ul>


Assuming that the list item is wide enough to accommodate both elements, we simply set the appropriate flow for em and span .

 #wrap li span {
 float: right;
 }
 #wrap li em {
 float: left;
 font-style: normal;
 }


Since the contents of the list item is completely "floating", it will go beyond the boundaries of this element. Accordingly, we need to prevent it in some way. For example, we can also set a wrap for the element itself in order to force it to display its “floating” descendants (as described in the previous article ). Thus, we will have to make the ul list itself “floating” so that everything is displayed normally ( note: here, I think the author went too far, it was enough to make the name on the left non-floating to avoid such tricks ).

 #wrap li {
 width: 100%;
 float: left;
 }


These styles, together with additional markup, will provide us with a completely acceptable appearance in Figure 2.

2.
Figure 2

I don’t provide the full markup code now; This is just a basic CSS and a completed unordered list, already fully described above. It will be much more interesting to consider how the shadow effect is made around such a list, it can be viewed in more detail in Figure 3.

3.
Figure 3

This is a simple technique that uses a container with a background color and a corresponding border color. Inside the container is the main element with its border and background color. We simply shift the internal element relative to the external, using relative positioning ( position: relative ) to show the background of the parent element in the lumen that appears due to the displacement. Relative positioning does not affect the flow of the document, so the parent container is still in a position calculated from the offsets of all elements.

 #wrap {
 width: 500px;
 border: 1px solid # eff2df;
 margin: 0 20px;
 float: left;
 background: # 809900;
 }
 #wrap ul {
 padding: 20px 40px;
 list-style: none;
 float: left;
 border: 1px solid # 4c7300;
 position: relative;
 left: -2px;
 top: -2px;
 background: # eff2df;
 color: # 4c7300;
 }


Although the ul list has no width specified, it will be stretched due to its descendants; but it’s usually better to make the element static, assign it a width. You can make a pretty cute shadow effect if you use the appropriate colors. The border of the container should be a little lighter than its background, it will add realism.

Connect the dots



But back to our task. The next step is to create dashed lines that "unite" the left and right sides of the text. We can achieve a line across the entire width of the list item if we just add the appropriate style for its lower border.

 #wrap li {
 border-bottom: 1px dotted # 000;
 float: left
 }


4.
Figure 4


It already looks good enough, but we need to hide the dotted line under the text from each edge (left and right), and slightly shift it vertically (so that it is a single whole with the text. This can be easily achieved using the relative positioning of the text a little bit because the relative positioning does not affect the flow ( flow ) of the document, the dotted line itself will not move anywhere, and the effect will be similar to the use of margins. (For more information on relative positioning, read here ).

It may seem to you that in this case it is enough to shift the text by a few pixels, but this will be too lightly. If we shift the text in this way, then when the font size is changed in the browser, the dotted line will become visible again. Therefore, we need to use em as units, which will increase the shift of the text in proportion to the font size, which will ensure correct overlapping of the dotted line for each of the edges.

Thus, by shifting the span and em down we provide coverage for the dotted line, which is what we need. However, this is not all!

Now the text is on top of the dotted line, but does not hide it. For the actual overlap, we need to set the background color for em and span . This color must match the current background color ( note: a list item or the entire list ) to ensure full compliance. We will also have to set the corresponding indent for these elements from below to level the displacement of the text itself down. All this will lead to the following:

 * {margin: 0; padding: 0}
 h1, h2 {padding: 10px 20px 0}
 #wrap {
 width: 500px;
 border: 1px solid # eff2df;
 margin: 0 20px;
 float: left;
 background: # 809900;
 }
 #wrap ul {
 padding: 20px 40px;
 list-style: none;
 float: left;
 border: 1px solid # 4c7300;
 position: relative;
 left: -2px;
 top: -2px;
 background: # eff2df;
 color: # 4c7300;
 }
 #wrap li {
 border-bottom: 1px dotted # 000;
 line-height: 1.0;
 margin: 0 0 .5em 0;
 position: relative;
 width: 100%;
 float: left
 }
 #wrap li span {
 background: # eff2df;
 padding: 1px 0 1px 5px;
 float: right;
 color: # 000;
 position: relative;
 top: .2em;
 }
 #wrap li em {
 float: left;
 margin: 0;
 position: relative;
 top: .2em;
 padding: 0 5px 0 0;
 background: # eff2df;
 font-style: normal;
 }


and html

 <div id = "wrap">
     <ul>
         <li> <em> Some text </ em> <span> ÂŁ 9.99 </ span> </ li>
         <li> <em> Some text a bit longer </ em> <span> ÂŁ 9.99 </ span> </ li>
         <li> <em> More text </ em> <span> ÂŁ 10.00 </ span> </ li>
         <li> <em> Other text a bit longer </ em> <span> ÂŁ 11.00 </ span> </ li>
         <li> <em> text </ em> <span> ÂŁ 12.00 </ span> </ li>
         <li> <em> Some text a bit longer </ em> <span> ÂŁ 9.99 </ span> </ li>
         <li> <em> More text </ em> <span> ÂŁ 10.00 </ span> </ li>
         <li> <em> Other text a bit longer </ em> <span> ÂŁ 11.00 </ span> </ li>
         <li> <em> text </ em> <span> ÂŁ 12.00 </ span> </ li>
     </ ul>
 </ div>


The figure shows the result:

5.
Figure 5

The current version can be seen here .

In this version, I used the universal eraser method ( * {margin: 0; padding: 0} ), but I would advise using more intelligent solutions so that, for example, the form element remains unchanged. For more information about the indentation and margins in browsers by default, you can read this note .

Saving ourselves from disaster



This is a pretty good example for relatively small code. You can change the font size, and the overall look will still be quite acceptable. If you are already tired of reading, then you can declare that your goal seems to have been achieved. However, it is worth thinking about what happens if the text on the left is longer than the width of the list item and is split into several lines. What happens to our layout?

This can be easily verified by simply adding some text to one of the list items. The result is shown below in Figure 6.

6.
Figure 6

Although the text remains readable, and nothing terrible seems to have happened, but the layout error is on the face, and our wonderful list flies to the cat's tail. We expect the text to be correctly split into two lines, and the dotted line will begin immediately after the end of the last line of text. It is also necessary that the price on the right remains at the end of the dotted line. The general view is shown in Figure 7.

7.
Figure 7

The description text is correctly transferred to the next line, and the dotted line begins immediately after its end and continues until the price on the right. Although it looks extremely simple, but on our way there will be a lot of new pitfalls. First, go back to Figure 6 and try to understand why the dotted line moved to the next line in relation to the text? It can be assumed that after the end of the text there is a gap, and this will be correct.

The problem is that we both have “floating” elements, which means that they will be stretched by their own content and will occupy all possible 100% of the width of the parent container, shifting the other “floating” elements to the next line. This is exactly what happened in Figure 6, when the description text stretched its container and took all available space, shifting the price down. If you ask about why the price slid down as much as two lines, the answer would be a rectangular shape of the “floating” element (text) that shifted it. The price simply cannot take its place, therefore it is located where it is.

It will be easier to understand if we circle the blocks with the text on the left with a red line (Figure 8).

8.
Figure 8

When the width of a “floating” block becomes 100%, it shifts the right “floating” block down with the dotted line. I repeat, there must be some simple and elegant solution that would provide a fixed width for the text, preventing it from crawling to the right side. Can we just calculate the optimal width of the text container, providing enough space for the right block, and just set it? However, as shown in Figure 9, the situation with the addition of a fixed width has only worsened!

9.
Figure 9

Firstly, it is worth noting that the dotted line now continues on to the right-most edge just because of the fixed width (it is “erased” by the background color of the left part). Secondly, the price is too high for a long text. Obviously, we can not use this method. But what should we do? Yeah ... But what if we try to remove the flow around the left side, making it static, and at the same time remove the width?

If we define the wrapping only for the right part, and the left one will be static, we will need, for a start, to change the order of their location in HTML (the right part must be before the content that it should flow around). (A small note: generally speaking, it should be possible to leave HTML unchanged in this case, since the wrapped blocks should be displayed in one line with linear ( inline ) elements. "Floating" elements shift only block ones down. However, these normally cope only Opera, so we still have to change our HTML.)

 <li> <span> ÂŁ 11.00 </ span> <em> Other text a bit longer </ em> </ li>


So, we moved the span with the price to the beginning of each line in HTML: we hope this will allow the rest of the text to flow around it. Figure 10 shows the corresponding change.

10.
Figure 10

Our model, apparently, is already very close to its final appearance, but now the price for a long description is shifted upwards. The price wraps around the text on the right, so nothing happens to the price itself if the text gets longer. How do we automatically move it down?

It seems that with each step we take we face a new problem, but, in fact, we are not approaching our goal (which is shown in Figure 7). It becomes obvious that initially we have chosen a not quite right direction, and the end result is achieved somewhat differently.

Using the current markup we will not be able to shift both the text and the price down if the description is divided into several lines. Therefore, we need to change it, and obviously shift the right block one line below the text. The description should have a block element (no wrap), this will ensure that the price will always be on the next line after it, even if the description takes several lines. This will give us confident behavior of the entire layout exactly as we need it. Then we can again use relative positioning to move the left block down.

The description and the right wrapped block now start each on its own line, as shown in Figure 11.

11.
Figure 11

Now we have a guarantee that the price will always be one line below the description. All we need is to move the description down to about the height of one line so that it is in the right place. If the offset and height of the line we have set in em , then we can be assured that when you change the font size, everything will change proportionally. It may take several attempts, not all of which will be successful to achieve this result, but it's worth it. We will also need to shift the price down a bit to close the dotted line, as in the first example. To do this, again, we use relative positioning, so the lower bound itself for the list elements will not move.

All this leads to an almost perfect picture with one small exception: now there is an additional gap of one line height between the elements of the list. This can be corrected by setting a negative top margin ( margin ) for the list item to close this offset. Obviously, for this we use em again, which will preserve the integrity of the layout and good scaling. Exact numbers may depend on your specific case, it may take several attempts to achieve the desired effect.

And finally, we need to eliminate the last discrepancy - we need the description to be transferred to the next line where it meets with the price, so that everything looks perfect. I added pad in the right side of p in 5em, which now contains em with the description text. I just assumed that 5em should be quite enough so that at any height of the line the description text does not fit the price.

Now we can arrange the HTML code in a more semantic order, with the result that the list item will look like this:

 <li>
     <p> <em> Other text a bit longer </ em> </ p>
     <span> ÂŁ 11.00 </ span> <em>
 </ li>


Now we have an additional element p (so that all browsers display the layout is similar to the behavior of Opera'y, which was described above), and the span is again located after the text, but already after the element p . (I left a span as a span , because we consider this example only as a demo version, more semantically in this case will use a block element, for example, p . This naturally entails applying style classes to distinguish between the first and second paragraph or use in one case of div instead of p for the uniqueness of the tags. But for the sake of greater clarity and transparency of the whole process, I left the span .)

Let's go back to our example, let's see what the effect will be from the following CSS rules. I left only those that have changed, if you need the code completely, you can look it through the link “working version” at the end of the article.

 #wrap li <font> {
 line-height: 1.2;
 margin: -. 9em 0 0 0;
 position: relative;
 float: left;
 width: 100%;
 text-align: left;
 border-bottom: 1px dotted # 000;
 clear: both;
 }
 * html #wrap li {
 border: none;
 background: url (images / dotted-leader.gif) repeat-x left bottom;
 }
 #wrap li span {
 background: # eff2df;
 padding: 1px 0 1px 5px;
 color: # 000;
 position: relative;
 top: .4em;
 float: right;
 }
 #wrap li em {
 margin: 0;
 position: relative;
 top: 1.6em;
 padding: 0 5px 0 0;
 background: # eff2df;
 }
 #wrap p {padding: 0 5em 0 0}


The result is shown in Figure 12 below.

12.
Figure 12

Hmm ... looks great!

The screenshot above was taken in Firefox 2.0, I wonder what it looks like in IE6?

So...

13.   IE6
Figure 13

It looks very good, but what happened to our wonderful dotted border? It looks like a set of dashes, not points, which does not match the design. This is a problem of older versions of IE, when IE6 (and earlier) display dashes instead of points for the border, when the border size is 1 pixel. We can't do anything about it. Or can we?

In fact, we can force IE6 to display our layout much better if we remove the border altogether, and instead use the background image. We can apply these styles for IE6 and earlier versions as follows:

 * html #wrap li {
 border: none;
 background: url (images / dotted-leader.gif) repeat-x left bottom;
 }


The border is removed for the list item, a background image is added instead. Selectors starting with * work only for IE6 and below.

This code has already been added to CSS above, the working version can be viewed here . Open the page source and just copy the code. All CSS is left right in the HTML document for convenience.

Try to change the font size, the layout looks very stable, and the overall layout does not fall apart. To see how it looks in different browsers, you can use the following service .

Thanks to all who read to the end of this note. It would be great if you share your thoughts and thoughts on the topic.

Web Optimizator: checking the speed of loading sites

Source: https://habr.com/ru/post/31341/


All Articles