Responsiivisen verkkosivuston luominen CSS Gridillä ja Flexboxilla

Responsiivisen verkkosivuston luominen CSS Gridillä ja Flexboxilla

Tämä esimerkki toteuttaa responsiivisen verkkosivuston suunnittelun CSS:n, HTML:n ja JavaScriptin avulla. Asettelusta on kaksi muunnelmaa, jotka sopivat sekä työpöytäselaimille että mobiililaitteille.

Perusasetukset

Aloita indeksillä.css ja index.html Grid CSS:n pyhän graalin asettelusta.

Sijoita index.css ja index.html samaan kansioon. Avaa index.html verkkoselaimessa.

Pyhä malja

Ulkoasun suunnittelu

Esimerkkimme näyttää yhden tavan luoda kotisivu kuvitteelliselle yritykselle/palvelulle. Kotisivu on ensimmäinen asia, jonka käyttäjä näkee vieraillessaan sivustolla.

Sisällön pääpiirteet

Kotisivulla näkyvät ensisijaiset tiedot on lueteltu alla.

  • Nimi/logo — Yrityksen/palvelun identiteetti otsikossa vasemmalla tasattuina.
  • Ilmoitukset – pääosan ensimmäinen osa. Käyttäjä näkee nämä tiedot sivun yläpuolella, ennen kuin hän näkee myytäviä kohteita. Tämä tila voi sisältää tärkeitä päivityksiä, rajoitetun ajan tarjouksia tai suositeltuja kohteita.
  • Myytävät kohteet – erilaisten myytävien tuotteiden nimi, kuvaus, hinta ja nykyinen varasto.
  • Tulevat tapahtumat — Tietoja tulevista liiketoimintaan liittyvistä tapahtumista, joihin käyttäjä saattaa haluta osallistua.
  • Päivän viesti — Pyörivä “makusisältö”, kuten tietokilpailu tai inspiroiva lainaus.
  • Alatunniste — Tekijä- ja/tai tekijänoikeustiedot.

Alasisällön pääpiirteet

Seuraavat linkit ja lisätiedot ovat saatavilla kotisivulla, mikä rohkaisee käyttäjää tutkimaan. Tämä alisisältö voi näkyä ulkoasussa eri tavalla käyttäjän katselulaitteen mukaan.

  • Pöytätietokoneen selaimessa tai mobiililaitteessa vaakatilassa kaikki alisisältö näytetään.
  • Mobiililaitteessa pystytilassa tai kapeaksi muutetun työpöydän selainikkunan sivupaneelit katoavat. Alasisältö on sijoitettu uudelleen tai se on saatavilla valikossa.

Seuraava alisisältö on käytettävissä kotisivulla.

  • Tietoja — Linkki erilliselle henkilöllisyysselvityssivulle. Työpöytä/maisema-tilassa se näkyy otsikossa, tasattu oikealle. Muotokuvatilassa se on valikkokohta.
  • Yhteystiedot — Linkki erilliselle sivulle, jolla on yrityksen/palvelun yhteystiedot, kuten postiosoite, sähköpostiosoite, puhelinnumero jne. Työpöytä-/vaakatilassa tämä linkki näkyy otsikossa, oikealla. Muotokuvatilassa se on valikkokohta.
  • Osiot — Linkit verkkosivuston muihin osiin. Pystykuvatilassa jokainen osion linkki on valikkokohta.
  • Yhteistyökumppanit — Linkit kumppaniyrityksille/palveluille. Työpöytä-/maisematilassa kumppanit näkyvät oikeanpuoleisessa paneelissa. Muotokuvatilassa ne näkyvät päärungon alaosassa.

Asettelukaavio

Tässä mallissa on kaksi asetteluvaihtoehtoa.

  • Yksi asettelu vaakatilassa oleville laitteille.
  • Yksi asettelu laitteille pystytilassa.

Työpöytäselaimet ovat yhteensopivia molempien kanssa, mutta näyttävät ensisijaisesti vaaka-asettelun.

Asettelut on kuvattu seuraavasti.

Maisemakaavio

Muotokuva kaavio

HTML-elementtejä

Tässä suunnittelussa seuraaville HTML-elementeille on jokaiselle määritetty erityinen asettelun tarkoitus.

Elementti Tarkoitus
Jako tai div-elementti on asettelun perusrakennuspalikka. Koko sivu sisältyy diviin, mukaan lukien komponenttiruudukon kohteet (otsikko, paneelit, pääteksti, alatunniste). Div voi sisältää toisen div.
Sisältää ainutlaatuisen tietoosion, kuten “Ilmoitukset”, “Myytävät kohteet” jne. Tässä asettelussa pääosa on toteutettu osioiden osana.

Suurin otsikkoteksti, jota käytetään verkkosivuston nimessä.

Suuri otsikkoteksti, jota käytetään navigointikohdissa (Tietoja, Yhteystiedot).

Keskikokoinen otsikkoteksti, käytetään osioiden otsikoissa (Ystävämme, Ilmoitukset).

Pieni otsikkoteksti, jota käytetään sisällön otsikoissa (Open for business, Cider fest).
Tekstin kappale, jonka odotetaan siirtyvän seuraavalle riville.
Valikoima vaihtoehtoista tekstiä, joka ei katkaise kappaletta.
Taulukkotiedot, jotka on järjestetty riveihin ja sarakkeisiin, kuten myytävät tuotteet.

Flexbox

CSS Flexible Boxes (lyhennettynä Flexbox) on joukko erityisiä CSS-attribuutteja. Se luo elementtejä, jotka laajenevat tai supistuvat (“flex”) automaattisesti niiden sisällön ja asettelukontekstin mukaan.

Attribuuttinäytöllä varustettu elementti: flexbox on flexbox-säilö. Jos säilön muoto muuttuu (esim. jos käyttäjä muuttaa selainikkunan kokoa tai kääntää mobiililaitettaan), sen alielementit muuttavat suhteellista sijaintiaan ja/tai muotoaan. Elementit taipuvat yhdessä ulottuvuudessa, joko vaakasuunnassa (rivissä) tai pystysuunnassa (sarakkeessa).

Graalin asettelussa on viisi pääaluetta, jotka taipuvat.

  • Ylä- ja alatunniste taipuvat vaakasuunnassa (flex-direction: rivi), vasemmalta oikealle.
  • Vasen paneeli, päärunko ja oikea paneeli taipuvat pystysuunnassa (joustosuunta: pylväs), ylhäältä alas.

Maisema flex

Muotokuvatilassa paneelit ovat piilossa. Valikko on toteutettu joustavana sarakkeena.

Portrait flex

Toteutus: CSS, JavaScript ja HTML

CSS: index.css

/* element styles */
* {
  margin: 0;     /* by default, all elements (selector *) have no margin */
}
html {
  width: 100%;                    /* 100% width of parent (root) element */
  height: 100vh;                              /* 100% height of viewport */
  background: rgb(0, 0, 0, 0.1);                            /* 10% black */
  font-size: 1.0em;                                /* our root font size */
  font-family: Arial, Helvetica, sans-serif;             /* default font */
}
body {
  min-height: 100%;
}
section {
  padding: 0.5rem;
  flex-grow: 1;         /* in a flexbox, sections expand along flex axis */
}
h1 {                                           /* Website name in header */
  font-size: 2.0rem;
  font-weight: normal;
}
h2 {                                                   /* About, Contact */
  font-size: 1.25rem;
}
h3 {                                                 /* Section headings */
  font-size: 1.2rem;
  padding: 0.5rem;
}
h4 {                                               /* Section item title */
  font-weight: normal;
  padding: 0.5rem;
}
p {                                                 /* Paragraph styling */
  padding: 0.5rem;
}
a:link, a:visited {            /* anchor links, and visited anchor links */
  color: black;
  text-decoration: none;                            /* disable underline */
}
a:hover {                                 /* when anchor link is hovered */
  color: rgb(25, 25, 25);
}
a:active {                                /* when anchor link is clicked */
  color: rgb(96, 96, 96);
}
/* component styles */
#container {
  display: grid;
  height: 100%;
  grid-template-columns:
    [left] 10rem auto 10rem [right];
  grid-template-rows:
    [top] 5rem auto 5rem [bottom];
  grid-template-areas:
    "head head head"
    "panleft mainbody panright"
    "foot foot foot";
}
#header {
  grid-area: head;                  /* corresponds to grid-template-area */
  background: rgb(0, 0, 0, 0.2);                            /* 20% black */
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: baseline;  /* site name and nav item text aligns baseline */
  padding: 1.0rem;
}
#panel {                                        /* if element id="panel" */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: column;          /* its child elements flex vertically */
  padding: 0.5rem;
  background: rgb(0, 0, 0, 0.1);                            /* 10% black */
}
#panel.left {                  /* if element id="panel" and class="left" */
  grid-area: panleft;                  /* this element fills a grid area */
}
#panel.right {                /* if element id="panel" and class="right" */
  grid-area: panright;                 /* this element fills a grid area */
}
#footer {                                      /* if element id="footer" */
  grid-area: foot;                     /* this element fills a grid area */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: column;          /* its child elements flex vertically */
  justify-content: center;           /* horizontal center footer content */
  align-items: center;                 /* vertical center footer content */
  padding: 0.5rem;
  background: rgb(0, 0, 0, 0.2);
}
#mainbody {                                  /* if element id="mainbody" */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: column;          /* its child elements flex vertically */
  grid-area: mainbody;
  justify-self: center;          /* fixed-width mainbody always centered */
  width: 100%;
  min-width: 22.5rem;               /* mainbody width can't go < 22.5rem */
}
div#panel,
div#mainbody {                               /* extra space under header */
  padding-top: 0.5rem;
}
#partners, #sections {      /* if element id="partners" or id="sections" */
  display: flex;                     /* this element is a flexbox parent */
  flex-direction: row;           /* its child elements flex horizontally */
  flex-wrap: wrap;           /* its child elements can wrap to next line */
  align-content: flex-start;       /* child elements start in upper left */
}
#partners.wide {            /* if element id="partners" and class="wide" */
  display: none;              /* by default, do not display this element */
}
#menu {
  position: absolute;      /* menu position unaffected by other elements */
  right: 0;                       /* zero pixels from the right boundary */
  background: rgb(239, 239, 239);
  border: 0.15rem solid rgb(0, 0, 0, 0.4);
  visibility: hidden;        /* visibility property supports transitions */
  opacity: 0;      /* opacity + visibility transition = menu fade effect */
  z-index: 1;              /* ensure menu appears over all other content */
}
#menuitems {               /* menu is implemented as a flexbox container */
  display: flex;
  flex-direction: column;
  padding: 1rem;
}
#menuitems h3 {
  border-top: 0.15rem solid rgb(0, 0, 0, 0.1);  /* light horizontal rule */
}
#menuitems .menusec {
  border-color: rgb(0, 0, 0, 0.25);            /* darker horizontal rule */
}
#menuitems h3:hover {
  background-color: rgb(0, 0, 0, 0.1);     /* gray of rollover menuitems */
}
.menubutton {
  text-align: right;
  cursor: pointer;            /* indicates it can be clicked like a link */
  user-select: none;            /* user cannot select the button as text */
}
#menuitems .alignright {
  text-align: right;            /* right-aligned menu item text (unused) */
}
#header h1.menubutton {
  display: none;        /* in default view (landscape), hide menu button */
  border: 0.15rem solid rgb(0, 0, 0, 0);   /* (invisible) alignment shim */
}
#header .placeholder {    /* this invisible button is rendered when menu */
  color: rgb(0, 0, 0, 0); /* button is hidden, so header height matches. */
  user-select: none;       /* user can't select text of invisible button */
}
.sectionlink, .partnerlink {
  border-radius: 0.25rem;     /* give this element a slight rounded edge */
  font-weight: normal;
  font-size: 1.1rem;
  padding: 0.5rem;
  width: 7rem;                            /* fixed width for these items */
  margin-bottom: 1rem;                  /* slight margin for readability */
  background: rgb(0, 0, 0, 0.1);
}
.sectionlink:hover, .partnerlink:hover {
  background-color: rgb(0, 0, 0, 0.065);   /* brighten bg on mouse hover */
}
.partnerlink {
  height: 7rem;        /* partner elements are additionally fixed height */
}
.partnerlink.wide {
  margin: 0.5rem 1rem 0.5rem 0;      /* margins for spacing if they wrap */
}
.clickable-area {      /* use whenever a clickable area excludes margins */
  height: 100%;                 /* clickable area spans height of parent */
}
.eventitem, .announceitem, .motditem {
  margin-bottom: 0.5rem;                /* slight margin for readability */
}
.title {                                    /* e.g., "Open for business" */
  font-style: italic;
  font-weight: normal;
  font-size: 1.1rem;
}
.date {                                         /* e.g., January 1, 2021 */
  font-style: italic;
  font-size: 0.9rem;
  padding: 0 0 0 0.5rem;
  color: rgb(0, 0, 0, 0.5);
}
.navitem {                                             /* About, Contact */
  font-weight: normal;
  padding: 0 0.5rem 0 1rem;
}
.headspace, .panspace, .footspace, .bodyspace {
  flex-grow: 1;      /* these elements expand on flex axis to fill space */
}
/* table styles ("items for sale") */
table {
  border-collapse: collapse;               /* pixel-adjacent table cells */
  width: 100%;
  margin-bottom: 1rem;
}
th {
  text-align: left;
}
tr {
  margin: 4rem 0 0 0;
  border-bottom: 0.15rem solid rgb(0, 0, 0, 0.2);     /* horizontal rule */
}
td, th {
  padding: 0.5rem;
  vertical-align: top;
}
td.price {
  white-space: nowrap;        /* white space in price does not wrap line */
}
td.qty, th.qty {
  text-align: center;
}
span.perunit {
  opacity: 0.5;
}
/* responsive styles applied in portrait mode */
@media screen and (max-width: 45rem) {      /* if viewport width < 45rem */
  #panel.left {
    grid-column-end: left;         /* panel grid area shrinks to nothing */
  }
  #panel.right {
    grid-column-start: right;      /* panel grid area shrinks to nothing */
  }
  #partners.tall {
    display: none;  /* hide partners in panel (overwrites display: flex) */
  }
  #partners.wide {
    display: flex;   /* show partners in body (overwrites display: none) */
  }
  #panel,                                 /* these disappear from layout */
  #header .placeholder,
  .navitem {
    display: none;
  }
  #mainbody {
    grid-column-start: left;         /* mainbody now starts at left edge */
    grid-column-end: right;           /* mainbody now ends at right edge */
  }
  #header h1.menubutton {              /* display the header menu button */
    display: inline;                         /* overwrites display: none */
  }
}

JavaScript: index.js

Tämä JavaScript toteuttaa valikon Näytä/piilota-kytkimen, joka laukeaa, kun valikkopainiketta painetaan.

function menuToggle(state) {
  var ele = document.getElementById('menu');
  switch(state) {
    case 'show':
      ele.style.opacity=1;
      ele.style.color="rgb(96, 96, 96)";
      ele.style.visibility='visible';
      ele.style.transition='visibility 0s, opacity 0.3s';
      break;
    case 'hide':
      ele.style.opacity=0;
      ele.style.color="black";
      ele.style.visibility='hidden';
      ele.style.transition='visibility 0.3s, opacity 0.3s'; 
      break;
  }
}

HTML: index.html

<!DOCTYPE html>
<html lang="en">
 <head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta charset="utf-8">
  <title>Title</title>
  <link rel="stylesheet" href="index.css">
  <script src="index.js"></script>
 </head>
 <body>
  <div id="menu">
   <section id="menuitems">
    <div class="menubutton">
     <h1 onclick="menuToggle('hide')" class="menubutton">☰</h1>
    </div>
    <p><!-- space above first menu item --></p>
    <a href="javascript:void(0);"><h3 class="menusec">Tips for living well</h3></a>
    <a href="javascript:void(0);"><h3>Recipes</h3></a>
    <a href="javascript:void(0);"><h3>Homesteading advice</h3></a>
    <a href="javascript:void(0);"><h3 class="menusec">About Us</h3></a>
    <a href="javascript:void(0);"><h3 class="menusec">Contact Us</h3></a>
   </section>
  </div>
  <div id="container">
   <div id="header">
    <a href="javascript:void(0);"><h1 class="logo">Our Farm Stand</h1></a>
    <div class="headspace"></div>
    <h1 onclick="menuToggle('show')" class="menubutton">☰</h1>
    <h1 class="placeholder">☰</h1>
    <h2 class="navitem">
     <a href="javascript:void(0);">
      <div class="clickable-area">About Us</div>
     </a>
    </h2>
    <h2 class="navitem">
     <a href="javascript:void(0);">
      <div class="clickable-area">Contact Us</div>
     </a>
    </h2>
   </div>
   <div id="panel" class="left">
    <section id="sections">
     <div class="sectionlink">
      <a href="javascript:void(0);">
       <div class="clickable-area">Tips for living well</div>
      </a>
     </div>
     <div class="sectionlink">
      <a href="javascript:void(0);">
       <div class="clickable-area">Recipes</div>
      </a>
     </div>
     <div class="sectionlink">
      <a href="javascript:void(0);">
      <div class="clickable-area">Homesteading advice</div>
      </a>
     </div>
    </section>
   </div>
   <div id="mainbody">
    <section class="mainbodyitems">
     <h3>Announcements</h3>
     <section class="announcements">
      <div class="announceitem">
       <h4 class="title">Open for business</h4>
       <p class="date">Jan. 15</p>
       <p>Renovations of our new storefront are complete, and we're open for business.</p>
      </div>
     </section>
     <h3>Items for sale</h3>
     <section class="forsaleitems">
     <table>
      <tr>
       <th>Item</th>
       <th>Description</th>
       <th>Price</th>
       <th class="qty">Qty</th>
      </tr>
      <tr>
       <td>Milk</td>
       <td>Good source of calcium.</td>
       <td class="price">$2 <span class="perunit">/ half gal.</span></td>
       <td class="qty">3</td>
      </tr>
      <tr>
       <td>Eggs</td>
       <td>Great for breakfast and baking.</td>
       <td class="price">$4 <span class="perunit">/ doz.</span></td>
       <td class="qty">6</td>
      </tr>
      <tr>
       <td>Whole chicken</td>
       <td>Perfect for roasting.</td>
       <td class="price">$5 <span class="perunit">/ lb.</span></td>
       <td class="qty">4</td>
      </tr>
     </table>
    </section>
    <h3>Upcoming events</h3>
    <section>
     <div class="eventitem">
     <h4 class="title">Cider Fest</h4>
     <p class="date">October 20, 2pm–6pm</p>
     <p>Celebrate the season with fresh-pressed cider from our orchards.</p>
    </div>
    <div class="eventitem">
     <h4 class="title">Bread baking workshop</h4>
     <p class="date">December 13, 9am–noon</p>
     <p>Learn how to create and cultivate a sourdough starter.</p>
     </div>
    </section>
    <h3>Message of the day</h3>
    <section>
     <div class="motditem">
      <p>Eat better food. Support your local farm stand.</p>
     </div>
    </section>
    <h3 id="partners" class="wide">Our friends</h3>
    <section id="partners" class="wide">
     <div class="partnerlink wide">
      <a href="javascript:void(0);">
       <div class="clickable-area">Green Valley Greens</div>
      </a>
     </div>
     <div class="partnerlink wide">
      <a href="javascript:void(0);">
       <div class="clickable-area">Turkey Hill Farm</div>
      </a>
     </div>
     <div class="partnerlink wide">
      <a href="javascript:void(0);">
       <div class="clickable-area">Burt's Maple Syrup</div>
      </a>
     </div>
     <div class="partnerlink wide">
      <a href="javascript:void(0);">
       <div class="clickable-area">Only Organic Seeds</div>
      </a>
     </div>
    </section>
    <div class="bodyspace"></div>
   </section>
  </div>
  <div id="panel" class="right">
   <h3>Our friends</h3>
   <section id="partners" class="tall">
    <div class="partnerlink">
     <a href="javascript:void(0);">
      <div class="clickable-area">Green Valley Greens</div>
     </a>
    </div>
    <div class="partnerlink">
     <a href="javascript:void(0);">
      <div class="clickable-area">Turkey Hill Farm</div>
     </a>
    </div>
    <div class="partnerlink">
     <a href="javascript:void(0);">
      <div class="clickable-area">Burt's Maple Syrup</div>
     </a>
    </div>
    <div class="partnerlink">
     <a href="javascript:void(0);">
      <div class="clickable-area">Only Organic Seeds</div>
     </a>
    </div>
   </section>
   </div>
   <div id="footer">
    <p>Copyright © 2022 Alice &amp; Bob's Farm Stand</p>
   </div>
  </div>
 </body>
</html>

Ulkomuoto

Vaakanäkymässä paneelit näytetään.

Vaaka/työpöytänäkymä

Maisemanäkymä

muotokuvanäkymä

Pystynäkymässä paneelit ovat piilossa ja valikko on aktiivinen. Yhteistyökumppanit näytetään pääosan viimeisenä osana.

muotokuvanäkymä

Recent Articles

spot_img

Related Stories

Stay on op - Ge the daily news in your inbox

[tdn_block_newsletter_subscribe input_placeholder="Email address" btn_text="Subscribe" tds_newsletter2-image="730" tds_newsletter2-image_bg_color="#c3ecff" tds_newsletter3-input_bar_display="" tds_newsletter4-image="731" tds_newsletter4-image_bg_color="#fffbcf" tds_newsletter4-btn_bg_color="#f3b700" tds_newsletter4-check_accent="#f3b700" tds_newsletter5-tdicon="tdc-font-fa tdc-font-fa-envelope-o" tds_newsletter5-btn_bg_color="#000000" tds_newsletter5-btn_bg_color_hover="#4db2ec" tds_newsletter5-check_accent="#000000" tds_newsletter6-input_bar_display="row" tds_newsletter6-btn_bg_color="#da1414" tds_newsletter6-check_accent="#da1414" tds_newsletter7-image="732" tds_newsletter7-btn_bg_color="#1c69ad" tds_newsletter7-check_accent="#1c69ad" tds_newsletter7-f_title_font_size="20" tds_newsletter7-f_title_font_line_height="28px" tds_newsletter8-input_bar_display="row" tds_newsletter8-btn_bg_color="#00649e" tds_newsletter8-btn_bg_color_hover="#21709e" tds_newsletter8-check_accent="#00649e" embedded_form_code="YWN0aW9uJTNEJTIybGlzdC1tYW5hZ2UuY29tJTJGc3Vic2NyaWJlJTIy" tds_newsletter="tds_newsletter1" tds_newsletter3-all_border_width="2" tds_newsletter3-all_border_color="#e6e6e6" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjAiLCJib3JkZXItY29sb3IiOiIjZTZlNmU2IiwiZGlzcGxheSI6IiJ9fQ==" tds_newsletter1-btn_bg_color="#0d42a2" tds_newsletter1-f_btn_font_family="406" tds_newsletter1-f_btn_font_transform="uppercase" tds_newsletter1-f_btn_font_weight="800" tds_newsletter1-f_btn_font_spacing="1" tds_newsletter1-f_input_font_line_height="eyJhbGwiOiIzIiwicG9ydHJhaXQiOiIyLjYiLCJsYW5kc2NhcGUiOiIyLjgifQ==" tds_newsletter1-f_input_font_family="406" tds_newsletter1-f_input_font_size="eyJhbGwiOiIxMyIsImxhbmRzY2FwZSI6IjEyIiwicG9ydHJhaXQiOiIxMSIsInBob25lIjoiMTMifQ==" tds_newsletter1-input_bg_color="#fcfcfc" tds_newsletter1-input_border_size="0" tds_newsletter1-f_btn_font_size="eyJsYW5kc2NhcGUiOiIxMiIsInBvcnRyYWl0IjoiMTEiLCJhbGwiOiIxMyJ9" content_align_horizontal="content-horiz-center"]