Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature navbar #146

Closed
wants to merge 8 commits into from
Closed

Conversation

dallinbjohnson
Copy link
Contributor

@dallinbjohnson dallinbjohnson commented Apr 4, 2018

Brief description

reformatted the scss.

Developer Certificate of Origin

Sample pictures

...

Further details

...

@TotomInc TotomInc requested review from Fraham and rhyneav April 4, 2018 07:20
@TotomInc
Copy link
Contributor

TotomInc commented Apr 4, 2018

The new navbar looks great, but I think the bottom-border on each links is a bit too big. What are your thoughts @rhyneav?

@koester
Copy link
Contributor

koester commented Apr 4, 2018

The SCSS could still need a bit of cleanup. @dallinbjohnson you can further nest some selectors and use the resp mixing for the @media queries. Take a look at the &-operator to get an idea of how to nest class selectors and hovers

@dallinbjohnson
Copy link
Contributor Author

dallinbjohnson commented Apr 4, 2018

I have never worked with SCSS before and I looked at the resp mixin and I am not sure how to integrate it into my code. I did everything that I understood the rest is a little confusing to me. sorry. @koester
Thank you guys for being so patient with me and helping me out.

@koester
Copy link
Contributor

koester commented Apr 5, 2018

Being new or not knowing something is not a problem at all. We've all been there. When I'm at the office I'll edit this comment and explain how to use the resp mixing (or scss mixins in general) and give you some examples.

By just reading the code it's sometimes hard to see the bigger picture, especially when you're new to scss. I'll show you why this mixing exists and how it solves a common problem.

--

Ok let's dive into it. To ensure a consitent style in colors, breakpoints, sizes and general layout PaperCSS uses a special _config.scss where we defined those parameters, so everyone can use them in a new component. This allows you to design a component and automagically make it fit in with the rest of the components, just by using the $variables and @mixins the config provides. The @resp-mixin depends on a few variables.

// Responsive breakpoints
$large-screen: 1200px !default;
$medium-screen: 992px !default;
$small-screen: 768px !default;
$xsmall-screen: 480px !default;

These variables define the screen width of the most common breakpoints. These range from $large-screen: 1200px to $xsmall-screen: 480px. You could read them like this:

$large-screen: 1200px !default; // For Laptops
$medium-screen: 992px !default; // Tablets in landscape mode
$small-screen: 768px !default; // Tablets in portrait mode
$xsmall-screen: 480px !default; // Smartphones

Why did we define those? When you need a breakpoint to get your component to be responsive (just like you did with the @media screen (....) {...} declarations) we want to help you and make your life easier. When most of the components change at 768px, your navbar should probably follow that behaviour and change from a usual navigation to the mobile (burger) navigation. This helps keep a consistent style and the components feel "connected", as if they're all part of a bigger picture, even tho they may have been developed by completely different people.

So in theory you dont have to find out when your navbar should change "states", because the first time you probably want a burger navigation, instead of the usual navbar, is for tablet and smartphone devices. So you could just write something like this:

@media (max-width: $small-screen) {
  nav .collapsible .collapsible-body {
    display: contents;
  }
}

and the SCSS compiler will translate it for you to:

@media (max-width: 768px) {
  nav .collapsible .collapsible-body {
    display: contents;
  }
}

Nice! Now we dont have to remeber the 768px breakpoint everytime we need it, because we know that the $small-screen variable will give us the right value. And this value will stay consistend for all components. Also, if you later find out that you dont need your design to change at 768px but maybe at 712px you dont have to go through every component and change every media query. All you have to do is go into the _config.scss and change the value of the '$small-sceen' variable ONCE. The change will affect every component that used this variable. If that's not the coolest fucking thing ever I dont know what is. But its still very tedious to write out the media-query eeeverytime we need this. In your component it may not seem obvious, since there are not many breakpoints. But think about a bigger component with styling for multiple subnavigations and dropdown menus. This could mean that you need a lot more breakpoints and things can get out of hand very quickly. Its also not really fun to maintain such code, since one change could mean you have to edit 90 lines of media-queries.

Thaaaat's where the @resp-mixin comes in. It gives you a shorthand to quickly define what breakpoint you need and allows you to nest it into the selector that you want to change at a specific screen width. This may sound a bit complicated but you'll see what I mean. First lets take a look at the mixin:

@mixin resp($max:null, $min:null) {
@if $max == large or $max == lg { $max: $large-screen; }
@if $max == medium or $max == md { $max: $medium-screen; }
@if $max == small or $max == sm { $max: $small-screen; }
@if $max == xsmall or $max == xs { $max: $xsmall-screen; }
@if ($min != null and $max != null) {@media only screen and (max-width: $max) and (min-width: $min) { @content; }}
@else if($max != null and $min == null){@media only screen and (max-width: $max) { @content; }}
@else if($min != null and $max == null){@media only screen and (min-width: $min) { @content; }}
@else { @error "no matching size found";}
}

This is how I read that code:

// A new mixin with the name 'resp' is defined and its arguments '$max' and '$min' are given a default value of null. That is if you include the mixin without providing any arguments, both of them will be null. If you provide just one, the other will default to null.
@mixin resp($max:null, $min:null) { 

// These if-conditions check if the first argument ($max) is either large, medium, small or xsmall or the shorter syntax lg, md, sm and xs. If you include the mixin with @include resp(large) {...} this if-condition will resolve to true. If it is true, the value of $max will change from null (the default) to $large-screen.
// In a sentance this would read as:
// Is $max equal to the string 'large' or 'lg'? If so, change the value of $max to $large-screen. If not, go on to the next line. Now lets see if $max is equal to the string 'medium' or 'md'. If so, change the value of $max to $medium-screen. If not, go on to the next.
  @if $max == large or $max == lg  { $max: $large-screen; }
  @if $max == medium or $max == md { $max: $medium-screen; }
  @if $max == small or $max == sm { $max: $small-screen; }
  @if $max == xsmall or $max == xs { $max: $xsmall-screen; }

// After those checks we check one last time if $min and $max are NOT null. This way we allow the user to use the mixin with a pixel, em or rem value for a custom breakpoint and also check if the mixin was included with atleast one parameter.
// If $min AND $max are not equal to null then the mixin will return @media only screen and (max-width: $max) and (min-width: $min) { ... }
  @if ($min != null and $max != null) {@media only screen and (max-width: $max) and (min-width: $min) { @content; }}

// If $max is not equal to null but $min is still null the mixin will return @media only screen and (max-wdith: $max) {...}
  @else if($max != null and $min == null){@media only screen and (max-width: $max) { @content; }}

// If $min is not equal to null but $max is still null the mixin will return @media only screen and (min-width: $min) { ... }
  @else if($min != null and $max == null){@media only screen and (min-width: $min) { @content; }}

// If not a single if condition before this line was met then it will throw an error.
  @else { @error "no matching size found";}
}

So how do we apply this now? Consider this simple example:

.box {
  width: 50%;
}

We have a Class with the name box and gave it a width of 50%. Now we check it in the browser and see that at 700px it would be best to change the width to 100%, to take the full width of the screen. We could do it the way you did it and throw in a @media-declaration and change the with of the class inside that. But lets use the power of scss and the resp mixin. With the mixin this could look like this:

.box {
  width: 50%;
  
  @include resp(small) {
    width: 100%;
  }
}

// CSS Output
.box {
  width: 50%;
}
@media only screen and (max-width: 768px) {
  .box {
    width: 100%;
  }
}

Doesn't that read a lot better? Just by looking at the code you know that the .box will change its width from 50% to 100% when the given screen size is met. The compiled CSS output will stay the same as to what you wrote before, but I didnt have to remember what exact value my width needed to be. I just used the variables defined in the config. This also allows for 'stacking' breakpoints. Maybe the box should be 75% for laptops? Sure:

.box {
  width: 50%;
  
  @include resp(medium) {
    width: 75%;
  }
  
  @include resp(small) {
    width: 100%;
  }
}

// CSS:
.box {
  width: 50%;
}
@media only screen and (max-width: 992px) {
  .box {
    width: 75%;
  }
}
@media only screen and (max-width: 768px) {
  .box {
    width: 100%;
  }
}

Again, just by reading the SCSS Code now it is made clear how the box will behave. The mixin allows you to set breakpoints in a fast and consistent manner and also "connect" the @media queries to the class you want to change, instead of having your class definitions at the top of the file and the media-queries at the bottom.
This mixin is "block"-scoped. So no matter how deep your rules are nested, the mixin will always correspond to the "block" it was included in. Another example:

nav {
  ul.inline {
    padding: 0;
    margin-bottom: 0;
    
    li {
      display: inline-block;
      margin: 0 .5rem;

      @include resp(small) { 
        margin: 0 1rem;
      }
      
      &:before {
        content: "";
      }
      
      a {
        font-size: 1.3rem;
      }
    }
  }
}

//CSS:
nav ul.inline {
  padding: 0;
  margin-bottom: 0;
}
nav ul.inline li {
  display: inline-block;
  margin: 0 .5rem;
}
@media only screen and (max-width: 768px) {
  nav ul.inline li {
    margin: 0 1rem;
  }
}
nav ul.inline li:before {
  content: "";
}
nav ul.inline li a {
  font-size: 1.3rem;
}

With nesting you can create a logical hierarchy and save yourself the time to write the same selector more than once.
So instead of:

nav ul.inline { ... }
nav ul.inline a { ... }
nav ul.inline h1 { ... }
nav ul.inline h2 { ... }
nav ul.inline p { ... }

You could just do

nav {
  ul.inline {
    a { ... }
    h1 { ... }
    h2 { ... }
    p { ... }
  }
}

This will give you the exact same css output above, but it is easier to read, easier to maintain and a lot faster to write. We could even take this a step further if we consider that the ul inide the nav may have more than just the .inline-class. This is where the &-operator will help us out. Usually the nesting rules in SCSS follow a hierarchy, as shown above. With the & operator we can counter this.
Example:

nav {
 ul {
   li { }
  }
}

So nav is the parent of ul and ul is the parent of li. Or the other way around li is inside of ul is inside of nav. In the DOM this would correspond to the following:

<nav>
  <ul>
    <li></li>
  </ul>
</nav>

With nesting selectors and & we can mimic this in our SCSS files. But what about a case where we dont want to go a level deeper but stay on the same level? How could we possibly say that the .inline class should not be inside of ul but on the ul element itself. This is how we do it:

nav {
 ul {
  &.inline {
    li { color: pink; }
   }
   li { color: blue }
  }
}

The &-operator treats the nested rule as if it was on the same level as its parent. This will give us the expected css:

nav ul.inline li {
  color: pink;
}
nav ul li {
  color: blue;
}

To really see what the SCSS compiler is doing to your code behind the scenes and how the SCSS code you write will translate to plain CSS I'd advice you to play around with https://www.sassmeister.com/. When I was starting to learn SCSS this was a great way to learn for me. Give it a try. Another great resource to learn SCSS is the official starter guide: http://sass-lang.com/guide

Try to apply the new things you've learned to your navbar component. I apologize for any spelling mistakes and if you still have some questions left or anything I just wrote is unclear feel free to ask.

-webkit-transform: rotate(45deg) translate(-8px, -9px);
transform: rotate(45deg) translate(-8px, -9px);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see a pattern here. Is there a way to further nest those selectors and reduce the duplicated code?

top: 0;
right: 0;
left: 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different Classes for the same parent? How could you nest them together so you only have one nav with everything else nested inside?

@rhyneav
Copy link
Member

rhyneav commented Apr 5, 2018

@koester where can I read more of your writing?

@TotomInc I think it looks good! Maybe we can play around with different border thicknesses, but overall I like the look.

@koester
Copy link
Contributor

koester commented Apr 5, 2018

I'm usually more of a reader than a writer. But for $5 I'll start a blog 😂🍻

@rhyneav
Copy link
Member

rhyneav commented Apr 5, 2018

@koester thoughtsofkoester.com

@koester
Copy link
Contributor

koester commented Apr 9, 2018

@rhyneav Oh shieeet, thats one hell of a domain name for a blog. Now I'm really thinking of starting one. Just this small problem remains.. what the hell should I blog about? 🤔

@dallinbjohnson Do you need further help? If there are still questions left feel free to ask.

@dallinbjohnson
Copy link
Contributor Author

Sorry I have not had time to work on this I am working and going to school. It's getting close to finals. I will make time to work on it though. Everything that you taught me was great it really helped me understand.

@dallinbjohnson
Copy link
Contributor Author

dallinbjohnson commented May 20, 2018

How do I create another pull request with the changes that I have made to my feture-navbar? @rhyneav

@rhyneav
Copy link
Member

rhyneav commented May 22, 2018

You can just add additional commits to this feature-navbar branch @dallinbjohnson

If you want a fresh PR, you can copy your feature-navbar branch and open a new PR with that:

git checkout -b feature-newnavbar feature-navbar
git push origin feature-newnavbar

Then open a new PR through Github.

@dallinbjohnson
Copy link
Contributor Author

what are the checks that are not successful? and is there anything else I need to change to make my code so it can be merged? @rhyneav

@rhyneav
Copy link
Member

rhyneav commented May 23, 2018

I think the checks are giving an error because of the way npm is being installed in the test runner. I'm working on the fix in another branch. I don't think they're breaking from anything you're adding, don't worry!

Before getting your code merged in, make sure you are working off of the develop branch. With this, in Github, request to merge into the develop branch (rather than master). Also, @koester gave some great advice about DRYing up your code. Could you refactor your _navbar.scss to what he recommended?

Copy link
Contributor

@koester koester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit:
Nevermind, you already fixed it. Very good job! I didnt see your last commit before I submitted my review, so dont mind what I just wrote 🎉

@dallinbjohnson
Copy link
Contributor Author

dallinbjohnson commented May 23, 2018

It should be fixed now! let me know if there are any more changes I need to make. @rhyneav @koester

@rhyneav
Copy link
Member

rhyneav commented May 24, 2018

Looks great @dallinbjohnson thank you for taking care of those edits! Since this PR and #145 are identical, I'll merge #145 into develop since it is already pointing at it.

Great work, very excited to have a navbar added to PaperCSS!

@rhyneav rhyneav closed this May 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants