Back to Freecodecamp

Design a Blog Post Card

curriculum/challenges/english/blocks/lab-blog-post-card/66eaddd04a9e533fba689001.md

latest11.1 KB
Original Source

--description--

In this lab, you'll practice how to style backgrounds and borders by creating a blog post card.

Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.

User Stories:

  1. You should have a div element with a class of blog-post-card to hold all of your card elements.
  2. Within the .blog-post-card element, you should have an image element with a valid alt attribute and text, and a class of post-img. You can use https://cdn.freecodecamp.org/curriculum/labs/cover-photo.jpg for the src attribute of the image.
  3. You should have a div with a class of post-content within the .blog-post-card element with the following:
    • An h2 element with a class of post-title and text for the title of your blog post.
    • A p element with a class of post-excerpt and text to summarize your blog post.
    • An a element with a class of read-more with the text Read More.
  4. You should set the body element's background color to a value other than white.
  5. You should apply the following styles to the .blog-post-card element:
    • A white background.
    • Rounded corners.
    • A width of your choice.
    • The text alignment of your choice.
  6. The .post-img element should be styled so that the image fills the card's entire width and has a bottom border.
  7. The .post-content element should be styled so that there is padding inside the card.
  8. The .post-title and .post-excerpt elements should have a text color other than the default and margins on all sides.
  9. The .read-more element should be styled like a button and have:
    • A text color other than the default.
    • A background color.
    • Margins on all sides.
    • Padding on all sides.
    • Rounded corners.
    • A display property set to inline-block.
    • A hover effect that changes its background color.

Note: Be sure to link your stylesheet in your HTML and apply your CSS.

--hints--

You should have a div with a class of blog-post-card.

js
assert.exists(document.querySelector("div.blog-post-card"));

You should have an img element with a class of post-img. Make sure your image has an alt attribute with text and a src attribute with a value.

js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);

const img = card.querySelector("img.post-img");
assert.exists(img);
assert.isString(img.alt);
assert.isNotEmpty(img.alt);
assert.isTrue(img.hasAttribute("src"));
assert.isNotEmpty(img.getAttribute("src"));

You should have a div with class of post-content.

js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);
const content = card.querySelector("div.post-content");
assert.exists(content);

You should have an h2 element with a class of post-title. Make sure it has some text content for the title of your blog post.

js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);

const content = card.querySelector("div.post-content");
assert.exists(content);

const postTitle = content.querySelector("h2.post-title");
assert.exists(postTitle);
assert.isString(postTitle.textContent);
assert.isNotEmpty(postTitle.textContent);

You should have a p with a class of post-excerpt. Make sure it has some text content to summarize your blog post.

js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);

const content = card.querySelector("div.post-content");
assert.exists(content);

const postExcerpt = content.querySelector("p.post-excerpt");
assert.exists(postExcerpt);

You should have an a element with a class of read-more.

js
const card = document.querySelector("div.blog-post-card");
assert.exists(card);

const content = card.querySelector("div.post-content");
assert.exists(content);

const readMore = content.querySelector("a.read-more");
assert.exists(readMore);

Your .read-more element should have the text Read More.

js
const el = document.querySelector("div.post-content a.read-more");
assert.exists(el);
assert.strictEqual(el.textContent.trim(), "Read More");

Your .blog-post-card element should have a border-radius property with a value (should not be 0 or a negative value).

js
const card = document.querySelector('.blog-post-card');
assert.exists(card);

const borderRadius = getComputedStyle(card).borderRadius;
assert.isAbove(parseInt(borderRadius), 0);

Your .blog-post-card element should have a white background.

js
const card = document.querySelector('.blog-post-card');
assert.exists(card);

const backgroundColor = getComputedStyle(card).backgroundColor;
const whiteColors = ['rgb(255, 255, 255)', 'rgba(255, 255, 255, 1)', '#ffffff', '#fff', 'white'];

assert.oneOf(backgroundColor.toLowerCase(), whiteColors);

Your body element should have a background color other than white.

js
const bodyBg = getComputedStyle(document.body).backgroundColor;
const whiteColors = ['rgb(255, 255, 255)', 'rgba(255, 255, 255, 1)', '#ffffff', '#fff', 'white'];

assert.isFalse(whiteColors.includes(bodyBg.toLowerCase()));

You should target .blog-post-card and set its width property.

js
assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".blog-post-card")?.getPropertyValue("width"));

You should target .blog-post-card and set its text-align property.

js
assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".blog-post-card")?.getPropertyValue("text-align"));

You should target .post-content and set its padding property.

js
assert.isNotEmpty(new __helpers.CSSHelp(document).getStyle(".post-content")?.getPropertyValue("padding"));

Your .read-more element should have a hover effect.

js
const link = document.querySelector('.read-more');
assert.exists(link);

const d = new __helpers.CSSHelp(document).getStyle('.read-more:hover');
assert.isNotEmpty(d.backgroundColor);

You should target .read-more and set its color property.

js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);

const readMoreTextColor = getComputedStyle(readMore).color;
assert.notStrictEqual(readMoreTextColor, 'rgba(0, 0, 0, 0)');

You should target .read-more and set its background-color property.

js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);

const readMoreBackgroundColor = getComputedStyle(readMore).backgroundColor;
assert.notStrictEqual(readMoreBackgroundColor, 'rgba(0, 0, 0, 0)');

You should target .read-more and set its margin property.

js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);

const readMoreMargin = getComputedStyle(readMore).marginTop;
assert.notStrictEqual(readMoreMargin, '0px');

You should target .read-more and set its display property.

js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);

const readMoreDisplay = getComputedStyle(readMore).display;
assert.strictEqual(readMoreDisplay, 'inline-block');

You should target .read-more and set its border-radius property.

js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);

const readMoreBorderRadius = getComputedStyle(readMore).borderRadius;
assert.notStrictEqual(readMoreBorderRadius, '0px');

You should target .read-more and set its padding property.

js
const readMore = document.querySelector('.read-more');
assert.exists(readMore);

const readMorePadding = getComputedStyle(readMore).padding;
assert.notStrictEqual(readMorePadding, '0px');

Your .post-img element should fill the card's width.

js
const postImg = document.querySelector('.post-img');
assert.exists(postImg);

const imgWidth = getComputedStyle(postImg).width;
const cardWidth = getComputedStyle(postImg.parentElement).width;
assert.closeTo(Number(imgWidth.replace(/px/ig, "")), Number(cardWidth.replace(/px/ig, "")), 15);

Your .post-img element should have a border-bottom value.

js
const postImg = document.querySelector('.post-img');
assert.exists(postImg);

const imgBorderBottom = getComputedStyle(postImg).borderBottomWidth;
assert.notStrictEqual(imgBorderBottom, '0px');

Your .post-title and .post-excerpt elements should have margins and non-default text colors.

js
const title = document.querySelector('.post-title');
const excerpt = document.querySelector('.post-excerpt');

function isColorApplied(element) {
  const color = getComputedStyle(element).getPropertyValue('color');
  return color && color !== 'rgba(0, 0, 0, 0)' && color !== 'transparent'; 
}

function isMarginApplied(element) {
  const margin = getComputedStyle(element).getPropertyValue('margin');
  return margin && margin !== '0px'; 
}

assert.isTrue(isColorApplied(title));
assert.isTrue(isMarginApplied(title));

assert.isTrue(isColorApplied(excerpt));
assert.isTrue(isMarginApplied(excerpt));

const styles = new __helpers.CSSHelp(document);
// Are CSS selectors used to style the elements:
const postTitle = [".post-title", ".post-excerpt, .post-title", ".post-title, .post-excerpt"].some(selector => {
  return !!styles.getStyle(selector)?.getPropVal('color');
});
const postExcerpt = [".post-excerpt", ".post-excerpt, .post-title", ".post-title, .post-excerpt"].some(selector => {
  return !!styles.getStyle(selector)?.getPropVal('color');
});
assert.isTrue(postTitle);
assert.isTrue(postExcerpt);

--seed--

--seed-contents--

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Blog Post Card</title>
</head>
<body>

</body>
</html>
css

--solutions--

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Blog Post Card</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="blog-post-card">
        
        <div class="post-content">
            <h2 class="post-title">Learn Web Development in 2024</h2>
            <p class="post-excerpt">Stay ahead of the curve with the latest trends in web development. Discover what's new and exciting in 2024</p>
            <a href="#" class="read-more">Read More</a>
        </div>
    </div>
</body>
</html>
css
body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
    font-family: Arial, sans-serif;
}

.blog-post-card {
    background-color: white;
    border-radius: 15px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    overflow: hidden;
    width: 350px;
    margin: 20px;
    text-align: center;
}

.post-img {
    width: 100%;
    height: auto;
    border-bottom: 5px solid #333;
}

.post-content {
    padding: 20px;
}

.post-title {
    color: #333;
    margin: 0 0 10px;
}

.post-excerpt {
    color: #667;
    margin: 10px 0;
}

.read-more {
    display: inline-block;
    margin-top: 10px;
    padding: 10px 15px;
    background-color: #333;
    color: white;
    text-decoration: none;
    border-radius: 5px;
}

.read-more:hover {
    background-color: #555;
}