You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
18 KiB

import { addBanner, addArticle, addTitle, addHeader, addParagraph, addClassParagraph, addSubHeader, addOrderedList, addUnorderedList, addBlockquote, addInset, addInsetList, addInsetCodeListing, addInsetBulletList, addImageWithCaption, addButtonGroup, addSidebar, addSyntax, menu, global_menu } from '/scripts/import.js';
import { local_menu } from '/scripts/webdev.js';
const heading = document.querySelector(".heading");
const global = document.querySelector(".global_menu");
const local = document.querySelector(".local_menu");
const sidebar = document.querySelector(".sidebar");
const main = document.querySelector(".main_content");
heading.append(addTitle("CSS Essential Training"));
heading.append(addParagraph("Christina Truong - LinkedIn Learning - October 2019"));
heading.append(addParagraph("Chapter 7 - Advanced Selectors"));
main.append(addSubHeader("Introduction to Advanced Selectors"));
main.append(addParagraph("The aims for this part of the course are to become more familiar with selectors, especially the more advanced selectors, become more accustomed to the way selectors work in general and to become more comfortable with the online documentation. As a general rule, a good idea when deciding on the best selector is to start with a general selector and then adapt it to be more specific as required."));
main.append(addSubHeader("Relational Selectors: Combinators"));
main.append(addParagraph("A combinator is a selector which uses the relationship between elements to target a specific element. A descendant selector is a good example of this as in the following."));
main.append(addInsetCodeListing([".example a {", " /* CSS declarations */", "}"]));
main.append(addParagraph("In this case, we are targeting any anchor tags that are nested inside an element with the class example."));
main.append(addParagraph("Similar to a descendant selector is a child selector. This uses the > symbol between the selectors."));
main.append(addInsetCodeListing([".example > a {", " /* CSS declarations */", "}"]));
main.append(addParagraph("Note that the spaces before and after the > symbol are optional but they do make the CSS a little easier to read. Whereas a descendant selector will target any element nested inside the first (as in the above example targeting any descendant of the parent (the parent being the first element in the selector which is .example in these examples), a child selector will only select an element if it is a direct descendant of the parent. Consider this little snippet of HTML."));
main.append(addInsetCodeListing(["<section class=\"ancestor\">", " <div class=\"parent\">", " <div class=\"parent\">", " <p>Paragraph 1</p>", " <p>Paragraph 2</p>", " </div>", "</section>"]));
main.append(addParagraph("Here, we have a <section> element with one child selector, the <div> element and two other descendant elements, the two paragraphs. The two paragraphs are both child elements of the <div>. If we want to target these paragraphs using a child selector, as the parent element is the <div>, this would give us"));
main.append(addInsetCodeListing([".parent > p {", " /* CSS declarations */", "}"]));
main.append(addParagraph("We can also target these elements with a descendant selector."));
main.append(addInsetCodeListing([".ancestor p {", " /* CSS declarations */", "}"]));
main.append(addParagraph("However, since the paragraphs are not child elements of <section>, we cannot target the paragraphs with a child selector like this."));
main.append(addInsetCodeListing([".ancestor > p {", " /* This won't work */", "}"]));
main.append(addParagraph("It is important to remember that this is a perfectly valid selector targeting any <p> element that happens to be a child element of the ancestor class, so you won't see any errors in the CSS. It just so happens that there are no elements in this example that match that selector. Using the wrong selector can therefore sometimes be a bit tricky to debug."));
main.append(addParagraph("We can also use a combinator to select a sibling element. To demonstrate this, I will add another element to our HTML sample."));
main.append(addInsetCodeListing(["<section class=\"ancestor\">", " <div class=\"parent\">", " <h2>Heading</h2>", " <p>Paragraph 1</p>", " <p>Paragraph 2</p>", " </div>", "</section>"]));
main.append(addParagraph("The new <h2> element is also a child of the parent and a sibling to the two paragraphs. There are two sibling combinators we can use, the adjacent sibling combinator (which uses a + sign) and the general sibling combinator (which uses a ~ symbol). The difference is that the adjacent sibling combinator only targets the element immediately after the first selector (the first sibling) and the general sibling combinator target all sibling elements. So"));
main.append(addInsetCodeListing(["h2 + p {", " /* Targets Paragraph 1 only */", "}"]));
main.append(addParagraph("and"));
main.append(addInsetCodeListing(["h2 ~ p {", " /* Targets Paragraph 1 and Paragraph 2 */", "}"]));
main.append(addParagraph("In the second example, the general sibling combinator will, of course, target any other paragraph that is also a sibling of the <h2> element."));
main.append(addParagraph("There is also a <a href=\"https://codepen.io/christinatruong/pen/xNWbjG?editors=1100\">codepen</a> demo for this section."));
main.append(addSubHeader(""));
main.append(addParagraph("In this section, we want to change some of the styles in the employment section. If you look at this in the previous version of the resume which was <a href=\"resumes/resume14.html\" target=\"_blank\">resume14.html</a>, notice that the Job title and the date look very similar. To emphasise the difference between the two, we want to apply different styles but at the same time, we also want to emphasise the fact that there is a relationship between the two by placing them closer together."));
main.append(addParagraph("Similarly, in the Education section, we want the paragraphs relating to each educational institute to be a little bit closer to the name of the institute. Again, we also want to emphasise the fact that the paragraphs represent different things (the first being the name of the qualification and the second being the name ofthe course."));
main.append(addParagraph("If you inspect the HTML code, you may notice that in the employment section (specifically the job details on the left), there is an &lt;h3&gt; element followed by several paragraphs. There are several ways to target the elements we want to style and in many ways, applying class names to the elements we want to change may be the easiest. However, it is not a particularly efficient approach since we would need to add the class to every element we want to target and it would be easy to miss one. Instead, we will use the combinator selectors we looked at earlier."));
main.append(addParagraph("In our CSS, this is going to be added to the global section since the styles are targeting elements in more than one section. Bear in mind that these elements are siblings, so we can use the adjacent sibling combinator to target the first paragraph after the heading like this."));
main.append(addInsetCodeListing(["h3 + p {", " font-style: italic;", "}"]));
main.append(addParagraph("To rremove the space between the paragraphs, we will set the margins to 0 and since this is a style that we want to apply to all of the paragraphs in the relevant sections, we can use the general sibling combinator like this."));
main.append(addInsetCodeListing(["h3 ~ p {", " margin: 0;", "}"]));
main.append(addParagraph("We also want to remove the space between the bottom of the heading and the paragrpahs, just to make each set of job details or educational items look a little more cohesive. This time, just a simple type selector will do."));
main.append(addInsetCodeListing(["h3 {", " margin-bottom: 0;", "}"]));
main.append(addParagraph("The order in which these selectors are placed within the CSS file will not affect the appearance of the page, but for the same reason that we split up the CSS file into difference sections (namely for the purpose of readability), these have been placed in a particualr order where we have the simplest first, h3, followed by the more specific sibling combinator, h3 + p and then the more general sibling combinator, h3 ~ p."));
main.append(addParagraph("Using sibling combinators like these can cause a problem. We have noted that the sections we want to target have a specific combination of elements (&lt;h3&gt; followed by one or more &lt;p&gt; elements, so the combinators will target the elements that we want to target. The problem is that we have other sections with a similar combination of HTML elements where we don't want these styles to be applied and the combinators will also target those elements."));
main.append(addParagraph("In order to fix this, we will need to make our selectors more specific. Remember that each section contains a &lt;div&gt; element with a class of content-wrap. We can't use that in our selectors because, again, it is also used in the sections we don't want to target. We do have a more specific class for job items but we want be as efficient as possible so we will add a new class to the &lt;div&gt; that contains the elements we want to target but only in the sections where we want to apply these styles. The name of the class is 'item-details'."));
main.append(addParagraph("We can now use a descendant selector where the ancestor is our class selector (.item-details) and the descendant is our sibling combinator (h3 + p or h3 ~ p), so our amended CSS selectors are"));
main.append(addInsetCodeListing([".item-details h3 + p {", " font-style: italic;", "}"]));
main.append(addParagraph("and"));
main.append(addInsetCodeListing([".item-details h3 ~ p {", " margin: 0;", "}"]));
main.append(addSubHeader("Pseudo-Class Selectors"));
main.append(addParagraph("For this section, we will look at the example in <a href=\"https://codepen.io/christinatruong/pen/OYvozj?editors=1100\">codepen</a>. The HTML at the start of the exercise is"));
main.append(addInsetCodeListing(["&lt;section&gt;", "&lt;!-- &lt;h1&gt;heading&lt;/h1&gt; --&gt;", "&lt;p&gt;Paragraph.&lt;/p&gt;", " &lt;p&gt;Paragraph.&lt;/p&gt;", " &lt;p&gt;Paragraph.&lt;/p&gt;", "&lt;!-- &lt;a href=\"#\"&gt;link&lt;/a&gt; --&gt;", "&lt;/section&gt;"]));
main.append(addParagraph("We have a &lt;section&gt; container with three child &lt;p&gt; elements. There are also two other elements, the &lt;h1&gt; heading and the &lt;a&gt; tag, both of which are commented out for the time being."));
main.append(addParagraph("The only CSS we have, initially, is a declaration to set the size of the text in the paragraphs to 20 pixels and we can see the initial state of the page on <a href=\"samples/pseudo1.html\" target=\"_blank\">pseudo1.html</a>."));
main.append(addParagraph("We saw pseudo class selectors before where these were associated with events, particularly relating to links such as a:visited. Here, we are looking at selectors that can be used to target a very specific element such as the first or last element or the first or last element of a specified type. Note that we can also add a parent selector to further refine the selection (for instance, to select the first or last element in a particular container)."));
main.append(addParagraph("Notice that the three paragraphs in pesudo1.html are all black. Now, we are going to use a selector to target the first and last child elements as follows."));
main.append(addInsetCodeListing(["p:first-child {", " color: red;", "}", "", "p:last-child {", " color: blue;", "}"]));
main.append(addParagraph("For an element to match either selector, it must match the first selector, p, and the pseudo selector, so it must be the first or last child element. We can see, in <a href=\"samples/pseudo1.html\" target=\"_blank\">pseudo1.html</a>, that this has indeed matched with the first and third (last) of those &lt;p&gt; elements. At first glance, you may wonder why this is different from a first-of-type or last-of-type selector and to help explain this, we will remove the comments around the two commented out elements so that they are enabled in the HTML. Without making any other changes, we can then check out the results in <a href=\"samples/pseudo3.html\" target=\"_blank\">pseudo3.html</a>."));
main.append(addParagraph("The paragraphs are now black again and the red colour is no longer being applied to any element. The link is blue, but that is only because blue is its default colour, it isn't picking this up from the CSS and, in fact, we can change this to green or any other colour and the link will still be blue."));
main.append(addParagraph("In pesudo3.html, none of the elements matched our selectors because there is no &lt;p&gt; element that is the first child or the last child. We will now change the selectors to first-of-type and last-of-type like this."));
main.append(addInsetCodeListing(["p:first-of-type {", " color: red;", "}", "", "p:last-of-type {", " color: blue;", "}"]));
main.append(addParagraph("This is shown in <a href=\"samples/pseudo4.html\" target=\"_blank\">pseudo4.html</a> where we can see that the first is red and the last paragraph is blue. The selectors here are similar to the first-child and last-child elements. In both cases, we are looking for a p that is the first child or last child. The difference is that in the first instance, the &lt;p&gt; element must be either the first or last child element in order to match but in the second instance, anything that is not an element of type p is ignored so we are only looking for the firsd or last child element of type p. This means that as long as we have at least one child element of type p, there will be a match. Of course, if we do have only one child element of type p, as shown in <a href=\"samples/pseudo5.html\" target=\"_blank\">pseudo5.html</a>, the paragraph is the first child element of type p so it will match the first-of-type selector, but it is also the last so it will also match the last-of-type selector and so the style that applies is quite simply the one that is applied last, so the colour of this paragraph is blue."));
main.append(addParagraph("Finally, to demonstrate that both of the selectors are matching the paragraph, I will switch them round so that the first-of-type selector is applied after the last-of-type selector and as we can see in <a href=\"samples/pseudo6.html\" target=\"_blank\">pseudo6.html</a>, the result is that our prargrpah is now red."));
main.append(addParagraph("Selectors is a topic in CSS that you can feel you have mastered once you have completed a few lessons or an introductory course, but this section demonstrates the fact that there is actaully a lot more complexity to selectors and there is a course given by Jen Kramer called <a href=\"https://www.linkedin.com/learning/css-selectors-2\">CSS: Selectors</a> which was published in May 2019. This covers the selectors we have seen so far as well as some more advanced options so it may be useful for both reinforcing and extending the learning in this course. This is part of the <a href=\"https://www.linkedin.com/learning/paths/learn-css\">Learn CSS</a> Learning Path which also incoude this CSS Essential Training Course as well as other advanced courses. There are 14 courses altogether in the Learning Path with around 27 hoursof video, so this is possibly something that is worth exploring once you are comfortable with CSS and want to extend your skillset."));
main.append(addSubHeader("Project: Advanced Selectors"));
main.append(addParagraph("Previously, we added some separator lines to the bottom of each section in Projects in the form of a border-bottom property with a value of dashed. We want to make some amendments to that. As it stands, it isn't really a separator since it is at the bottom of every project item, including the last one so it is actually acting more like a terminator. In addition, we want to use it more generally so that we can apply it to other sections as well."));
main.append(addParagraph("To make it more general, we are going to create a new class called divider. We will add this to the section in projects, but also the employment section. As with class-item previosuly, we are adding this to the &lt;section&gt; tag beacuse this contains all the elements in each of the sections."));
main.append(addParagraph("We can now use this divider class to set our border styles, but we don't want to set a border for every element in that container. You may recall that the &lt;div&gt; with this divider class is inside a &lt;section&gt; element but each project item or work item or work item is inside another section and these sections are nested within the &lt;div&gt;. We can use that parent child relationship to target all the sections containing either a project item or a work item and apply the relvant border styles like this."));
main.append(addInsetCodeListing([".divider &gt; section {", " border-bottom: 1px dashed #343434;", " padding: 25px 0;", "}"]));
main.append(addParagraph("If we look at the page with these changes ain <a href=\"resumes/resume15.html\" target=\"_blank\">resume15.html</a>, we can see that the border is at the bottom of each of the sections in both projects and work experience. But remember, we don't want this border to be applied to the last section element and we can remove it using a last-of-type selector. Now, essentially we are targeting the last element that had been styled with the border so we can take that selector ((.divider &gt; section), add the last-of-type pseudo class and use that to remove the border."));
main.append(addInsetCodeListing([".divider &gt; section:last-of-type {", " border-bottom: none;", "}"]));
main.append(addParagraph("So the first of these selectors targeted any element with type section that is a child (not ancerstor, it must be a child element) of a container with the divider class. The second selector is targeting the last child element of tyoe section that is a child of a container with the element class. We can see the result in <a href=\"resumes/resume16.html\" target=\"_blank\">resume16.html</a>."));
3 months ago
addSidebar("webdev");