One place for hosting & domains

      Explained

      Object-Oriented Programming Concepts, Explained


      Object-oriented programming gives you a set of programming principles to make your code more compartmentalized and reusable. Object-oriented programming accomplishes this by structuring programs around objects. This tutorial covers the core principles of of object-oriented programming and provides examples of these concepts written in Java.

      What is Object Oriented Programming (OOP)?

      Object-oriented programming — often abbreviated “OOP” — is a set of programming principles centered on objects. Such a set of principles is called a programming paradigm. Objects in OOP can hold attributes and be assigned behaviors, and they allow developers to structure programs around reusable, self-contained components.

      Because of its object-oriented focus, OOP shines when used for applications that need objects to be at their logical center. This is the case with user interfaces, one of the most common places to see OOP used, as well as business applications.

      OOP Concepts in Java You Need to Know

      Object-oriented programming tends to make use of four structures. These form the bedrock of all of the pieces a developer has to work with when building object-oriented programs.

      • Classes: These act as blueprints for objects. They define underlying properties and behaviors which can be inherited by other classes and by objects. Your OOP program’s collection of classes creates a structure off of which the rest of the program gets built.

        Often, in Java, code is constructed with one class per file. The class syntax resembles the following example:

        1
        2
        3
        4
        
        public class ClassName {
            // Code related to the class.
        }
            
      • Objects: These are derived from classes and populate the abstract of their classes’ properties with concrete values. They are the things built from the blueprints provided by classes. Objects also tend to be where the behaviors defined on classes get executed, bringing your application to life.

        Java lets you instantiate an object from a class using the new keyword. Here, a new object gets created from the class created above. This example works when the class has a constructor defined. You can see an example of a constructor definition in the
        Examples of Object Oriented Programming
        section further on.

        1
        2
        
        ClassName objectName = new ClassName();
            
      • Attributes: These are fields (or properties) defined on classes and which represent the state of a particular object. A class might, for instance, define an attributeOne as a String type. An object derived from that class can then use that attribute, assigning it attributeOne = "a string", for example.

        This next example shows what it could look like to add an attribute to the ClassName class created above:

        1
        2
        3
        4
        
        public class ClassName {
            public attributeOne = "a string";
        }
            
      • Methods: These are functions defined on classes, and they provide objects with behaviors. Methods typically act on the values held by an object’s attributes, allowing each object to act in a self-contained way.

        In the following example, you can see what it looks like to add a basic method to a class, using the ClassName example started above:

        1
        2
        3
        4
        5
        6
        7
        8
        
        public class ClassName {
            public attributeOne = "a string";
        
            public void methodOne() {
                System.out.println("The method has been called!");
            }
        }
            

      4 Basic OOP Principles

      In addition to the four basic parts, object-oriented programming has four fundamental concepts. These are what primarily make OOP stand out, and developers rely on these when making the most effective and reusable OOP code.

      These next four sections cover the four principles of OOP, giving you an overview of the roles they play. Then, keep reading to find a section with examples, in Java, each of which demonstrates these principles in action.

      Encapsulation

      This principle ensures that objects are self-contained and limits what information about their state they expose. In other words, other objects cannot directly access the state of an object. Each object manages its own state. To modify an object’s state, other objects need to use that object’s dedicated methods.

      So, for instance, say you have an object called firstObject. That object has two attributes, attributeOne and attributeTwo. Encapsulation prevents another object, say secondObject, from modifying the values of the attributes on firstObject.

      Now, firstObject has control of its own state. It may, for instance, define a method called setAttributeOne that outside objects can access. This way, secondObject can make changes to attributeOne on firstObject. But if firstObject does not define a similar method for attributeTwo, secondObject has no means of modifying it.

      Encapsulation can make OOP applications easier to upgrade and easier for collaboration. An engineer working on one object would thus be less likely to cause breaking changes to an object someone else is working on.

      Encapsulation also makes it easier to keep track of objects’ states. These states can become complicated, and more so the more outside access they allow. By ensuring that each object controls its own state, you make the code easier for yourself and other developers to follow and maintain.

      Data Abstraction

      This principle states that classes include only the details relevant to their context. Doing so creates abstract classes, which more specific classes and objects can extend.

      Take the example of a Pet class. You can make this class to define, in the most general way, the characteristics of pets. So, the class may have name, diet, and health attributes. Now you can extend that class with more specific kinds of Pet. For instance, you may define a Dog class that extends Pet and adds a bark method. At the same time, you can also define a Cat class similarly extending on Pet.

      One of the goals of abstraction is to define common characteristics. Using the example above, Dog has the unique behavior of the bark method, but otherwise it shares things like having a name in common with other pets. Abstraction makes it so that you do not need to redefine these attributes for each specific kind of pet.

      Abstraction also allows you to evaluate various classes by common abstract classes. So long as you know that both Cat and Dog extend Pet, you can evaluate them based on the common attributes held in Pet.

      1
      2
      3
      
      if (obj eitherCatOrDog instanceof Pet) {
          System.out.println("This is my pet, " + eitherCatOrDog.name + ".");
      }

      Inheritance

      This principle declares that objects get some or all of the properties of their parents. Inheritance is the foundation of reusability in OOP. With it, you can create a class and its properties can be reused in multiple objects.

      For example, you can start with a ClassName class from which you create two objects, objectOne and objectTwo. Each of these objects inherits from the parent class, ClassName, and receives all of its attributes and methods. The objects can then each individually work with those attributes and methods. But the important feature is that the ClassName class acts as a common and reusable base.

      In Java, such parent classes are called super classes. Commonly, classes inheriting from super classes are called sub classes. This means that you can make additional classes that inherit from super classes, so that you can have a chain of inheritance.

      Take a look at the Pet example above again. You have a Cat class and a Dog class that inherit from Pet, thus gaining its attributes. From there, you can create specific objects that inherit from the new classes:

      The new object inherits not only properties of the Dog class — like the bark method — but also those on the Pet class, like the name attribute.

      Polymorphism

      This principle states that each sub class can be used in the same way as its parent class or parent classes. At the same time, each sub class may keep its own, distinct form of attributes and methods initially defined in a super class.

      Polymorphism is one of the more complicated features of OOP, but it plays a useful role. To help you understand it, below is an example that reworks the Pet example elaborated in the sections above.

      Say, for instance, when creating the Pet class, you include a method called makeSound:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      class Pet {
          public String name = "None";
          public String diet = "Herbivore";
          public boolean healthy = true;
      
          public void makeSound() {
              System.out.println("This is my pet sound.");
          }
      }

      Obviously, the effect of makeSound should be different for Cat and Dog, even though both, being pets, do make sounds:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      
      class Cat extends Pet {
          public String diet = "Carnivore";
      
          public void makeSound() {
              System.out.println("Meow.");
          }
      }
      
      class Dog extends Pet {
          public String diet = "Omnivore";
      
          public void makeSound() {
              System.out.println("Bark.");
          }
      }

      Following polymorphism, you can, indeed, use any property from the Pet class on any object deriving from the Cat and Dog classes. The effect may be different — you get a different sound from the makeSound method — but all of the parts are still there.

      Examples of Object Oriented Programming

      This section includes snippets of code that give examples of OOP concepts in Java. These are aimed to simultaneously show off some of the components of OOP as well as the four core principles discussed above. The examples also familiarize you with the elements of Java that relate to OOP.

      Starting simple, this first example shows a single Java class, not counting the default Main class used to start up the program. This class covers all of the parts — class, object, attribute, and method — of OOP mentioned above.

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      
      // Create a class.
      class BookShelf {
          // Declare the class attributes.
          public int numberOfBooks;
      
          // Implement a constructor. This is used to create objects from the class,
          // which you can see done in the `Main` class below.
          public BookShelf(int initialNumberOfBooks) {
              numberOfBooks = initialNumberOfBooks;
          }
      
          // Provide a method to add more books to the shelf.
          public void addBooks(int numberToAdd) {
              numberOfBooks += numberToAdd;
          }
      
          // Provide a method to display the count of books on the shelf.
          public void showBookCount() {
              System.out.println("The shelf has " + numberOfBooks + " books.");
          }
      }
      
      class Main {
          public static void main(String args[]) {
              // Use the `BookShelf` class's constructor to create a BookShelf object;
              // it also lets us specify how many books the object starts with.
              BookShelf thisBookShelf = new BookShelf(5);
              thisBookShelf.addBooks(2);
              thisBookShelf.showBookCount();
          }
      }
      The shelf has 7 books.

      Now, this next example is a little more ambitious. It has three classes — again, not counting the Main class. The first, GamingConsole, acts as a super on which other classes can extend. That is exactly what the second class, PlayStation, does — extends on the GamingConsole class. The last class, PlayStation4, does the same, but with the PlayStation class as its direct parent.

      This chain of extensions lets the example demonstrate several of the concepts of OOP at once. Each extension shows the concept of abstraction in action. The PlayStation class is able to make use of both attributes and methods from its parent, demonstrating inheritance. And the PlayStation4 class illustrates polymorphism through its identification with the GamingConsole super class during construction in the Main class.

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      
      // Create a super class, from which the other classes ultimately extend.
      class GamingConsole {
          // Declare attributes.
          public String consoleType;
          public String currentGame;
      
          // Provide a cosntructor to set initial values.
          public GamingConsole(String initialConsoleType, String initialGame) {
              consoleType = initialConsoleType;
              currentGame = initialGame;
          }
      
          // Provide two methods that should be common to all gaming consoles.
          public void insertGame(String gameName) {
              currentGame = gameName;
          }
      
          public void playGame() {
              System.out.println("Starting up the " + consoleType + " console.");
              if (currentGame == "") {
                  System.out.println("No game in the console.");
              } else {
                  System.out.println("Playing " + currentGame + ".");
              }
          }
      }
      
      // Create a sub class for a specific category of gaming console.
      class PlayStation extends GamingConsole {
          // Declare attributes.
          public boolean controllerConnected;
      
          // Provide a constructor.
          public PlayStation(String initialGame, boolean initialControllerConnected) {
              super("PlayStation", initialGame);
              controllerConnected = initialControllerConnected;
          }
      
          // Provide a method unique to this category of gaming consoles. (This
          // feature is not actually unique to PlayStation consoles, but just
          // pretend for the purposes of illustration.)
          public void connectController(boolean isControllerConnected) {
              controllerConnected = isControllerConnected;
          }
      
          // Override the default `playGame` method with a specific implementation
          // for `PlayStation` objects.
          public void playGame() {
              if (controllerConnected == false) {
                  System.out.println("Connect a controller before playing.");
              } else {
                  super.playGame();
              }
          }
      }
      
      // Create another sub class for an even more specific category, this being
      // a type of PlayStation gaming console.
      class PlayStation4 extends PlayStation {
          // Provide a constructor.
          public PlayStation4(String initialGame, boolean initialControllerConnected) {
              super(initialGame, initialControllerConnected);
              consoleType = "PlayStation 4";
      
              initiateWelcome();
          }
      
          // Provide a specific method for PlayStation 4 consoles.
          public void initiateWelcome() {
              System.out.println("Welcome to " + consoleType + ".");
          }
      }
      
      
      
      class Main {
          public static void main(String args[]) {
              // Instantiate a `PlayStation4` object. Notice the polymorphism
              // implied by the fact that we can use `GamingConsole` to identify
              // the new object's type.
              GamingConsole thisConsole = new PlayStation4("", true);
      
              // Use the two methods inherited from the `GamingConsole` super class.
              thisConsole.insertGame("Minecraft");
              thisConsole.playGame();
          }
      }
      Welcome to PlayStation 4.
      Starting up the PlayStation 4 console.
      Playing Minecraft.

      Conclusion

      In this guide you learned the fundamental principles of object-oriented programming. The concepts covered were encapsulation, abstraction, inheritance, and polymorphism. Applying these concepts helps to ensure that you are making the most of what the paradigm can do.

      Throughout this tutorial, the focus has been on OOP related to Java. But keep in mind that these concepts apply anywhere that supports object-oriented programming.
      JavaScript
      ,
      Python
      , and
      Ruby
      are popular examples.

      More Information

      You may wish to consult the following resources for additional information
      on this topic. While these are provided in the hope that they will be
      useful, please note that we cannot vouch for the accuracy or timeliness of
      externally hosted materials.



      Source link

      Infrastructure as Code Explained


      Introduction

      Cloud computing provides on-demand computing resources, which are decoupled from physical hardware and necessary underlying configuration. Autonomous software systems provision these computing resources in the cloud to achieve the automation that cloud computing offers. Because of such automation, it’s possible to control and manipulate the available resources programmatically by interfacing with the cloud providers. This way, infrastructure changes (such as resource scaling) can be implemented more quickly and reliably and operated mostly without manual interaction, but still with the ability to oversee the whole process and revert changes if something does not go according to plan.

      Infrastructure as Code (IaC) is the approach of automating infrastructure deployment and changes by defining the desired resource states and their mutual relationships in code. The code is written in specialized, human-readable languages of IaC tools. The actual resources in the cloud are created (or modified) when you execute the code. This then prompts the tool to interface with the cloud provider or deployment system on your behalf to apply the necessary changes, without using a cloud provider’s web interface. The code can be modified whenever needed—upon code execution the IaC tool will take care of finding the differences between the desired infrastructure in code and the actual infrastructure in the cloud, taking steps to make the actual state equal to the desired one.

      For IaC to work in practice, created resources must not be manually modified afterward (an immutable infrastructure), as this creates discord between the expected infrastructure in code and the actual state in the cloud. In addition, the manually modified resources could get recreated or deleted during future code executions, and all such customization would be lost. The solution to this is to incorporate the modifications into the infrastructure code.

      In this conceptual article, we’ll explore the IaC approach, its benefits, and examples of real-world implementations. We’ll also introduce Terraform, an open source IaC provisioning tool. We’ll review Terraform’s role in this approach and how it compares to other IaC tools.

      Benefits of IaC

      With IaC, you can quickly create as many instances of your entire infrastructure as you need, in multiple provider regions, from a single source of truth: your declarative code. This has many advantages that ensures you’re creating resources consistently without error while reducing management and manual setup time.

      The main benefits of IaC are:

      • Deployment: removing the manual provisioning interaction with cloud providers means a quicker deployment speed.
      • Recovery: identifying issues in the configuration can mean quick recovery from failures.
      • Consistency: deploying resources are the same each time, resolving infrastructure fragility.
      • Modification: modifying resources can have a quick turnaround time.
      • Reusability: reusing parts of the infrastructure architecture in future projects.
      • Version Control: storing the infrastructure code in version control systems.
      • Visibility: writing configuration as code acts as documentation for the infrastructure.

      Within an IaC workflow you can repeatedly spin up infrastructure in a standardized fashion, which means software development and testing is a quicker process because development, staging, quality-assurance testing, and production environments are separated. You can repeat the process of writing code and testing it live by deploying the infrastructure as many times as needed. Once your written infrastructure fulfills all requirements, you can deploy it in desired cloud environments. When new requirements arise, you can reiterate the process.

      General IaC Workflow

      IaC, being based on code, should always be coupled with version control software (VCS), such as Git. Storing your infrastructure declarations in VCS makes it easily retrievable, with changes visible to everyone on your team, and provides snapshots at historical points, so you can always roll back to an earlier version if new modifications create errors. Advanced VCS can be configured to automatically trigger the IaC tool to update the infrastructure in the cloud when an approved change is added.

      You now know what the IaC approach is, and what benefits it brings. You’ll now learn about states, the resource tracking mechanism employed in IaC. Then, you’ll follow up with the role of Terraform and other tools using IaC.

      What is ‘state’?

      In an IaC environment, the term ‘state’ refers to the state of affairs of desired infrastructure resources in a deployment. There are at least three states at a given moment: the actual one in the cloud, the ideal state presented in code, and the cached state that the IaC tool maintains. The cached state describes the state in the cloud as it was when the code was last executed. Terraform allows you to deploy the same code multiple times, forming multiple states for each deployment.

      How State is Changed

      The actual state in the cloud (of the managed resources) should always be the same as the cached state of the tool. When executing the code, the tool will compare the ideal state with the cached one and apply the detected differences to the cloud. If the cached and actual states do not match, it’s highly likely that the execution will fail or that resources will be incorrectly provisioned.

      Role of Terraform in IaC

      Terraform is an open source IaC resource provisioning tool, written in Go and developed by Hashicorp. It supports multiple cloud providers, including DigitalOcean. The infrastructure definitions are written in the Hashicorp Configuration Language (HCL), and source code files written in it have the file extension tf.

      Terraform works by reading the code describing your infrastructure and generating a graph containing all resources with their mutual relationships. It then compares it to the cached state of the resources in the cloud, and prepares an execution plan that details what will be applied to the cloud, and in what order, to reach the desired state.

      The two main types of underlying components in Terraform are providers and provisioners. Providers are responsible for interacting with a given cloud provider, creating, managing, and deleting resources, while provisioners are used to execute specific actions on created remote resources or the local machine the code is executing on.

      Terraform supports managing basic cloud provider components, such as compute instances, load balancers, storage, and DNS records, though more providers and provisioners can be added, owing to its extensible nature.

      In IaC Terraform’s role is to ensure that the state of resources in the cloud is equal to the state expressed in code. It does not monitor the deployed resources, and its main focus is not on further bootstrapping of the provisioned compute instances with software and tasks. In the next section, you’ll learn how it compares to other tools and how they extend each other in a typical workflow.

      The IaC approach is widespread in modern deployment, configuration management, virtualization, and orchestration software. Docker and Kubernetes, the leading tools used for container creation and orchestration, both use YAML as their language for declaring the desired end result. On the other hand, Hashicorp Packer, a tool for creating snapshots of deployments, uses JSON to declare the template and variables from which a snapshot of the system will be built.

      Ansible, Chef, and Puppet, the three most popular configuration management tools, all use the IaC approach to define the desired state of the servers they manage.

      Ansible bootstraps provided servers according to a given playbook. A playbook is a textual file written in appropriate YAML, instructing Ansible what operations to perform on the existing target resources. Examples of such operations include running and starting services, installing packages using the system-provided package manager, or executing custom bash commands. To learn more about writing Ansible playbooks, read Configuration Managment 101: Writing Ansible Playbooks.

      Chef and Puppet both require central servers with agents installed on each of the managed ones. Unlike Ansible, Chef uses Ruby, and Puppet uses its own declarative language for describing the resources.

      Terraform is not mutually exclusive with other IaC tools and DevOps systems. Its strength is in provisioning hardware resources, rather than further software installation and initial server setup.

      Unlike configuration management tools such as Ansible and Chef, Terraform is not suitable for installing software on the target resources and setting up tasks. Instead Terraform offers providers for interacting with their supported resources.

      Terraform can work from a single machine and does not require central servers with client agents installed on the provisioned resources, unlike some other tools. It does not check their actual state and reapplies the configuration automatically, because its main focus is on provisioning them. A typical workflow is to provision the infrastructure resources using Terraform and then bootstrap them using a configuration management tool, if needed.

      For Chef, Terraform has a built-in provisioner that sets up its client agent on provisioned remote resources. With it you can automatically have all your provisioned servers added to the main server, from where you can additionally configure them using cookbooks, Chef’s infrastructure declarations. You can learn more about writing them in Configuration Management 101: Writing Chef Recipes.

      Conclusion

      This article covered the paradigms of the IaC approach, its advantages over traditional manual system administration, the basics of Terraform as an IaC resource provisioning tool, and how it compares to other popular infrastructure automation tools.

      If you’re looking to incorporate Infrastructure as Code into your workflow, check out our Terraform series to learn the fundamentals of using this tool in your development and deployment process.

      One way to start with Terraform is to read How To Structure Your Terraform Project to understand how to ensure your infrastructure stays scalable and extensible.



      Source link

      CSS Units Explained


      While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or
      edited it to ensure you have an error-free learning experience. It’s on our list, and we’re working on it!
      You can help us out by using the “report an issue” button at the bottom of the tutorial.

      Introduction

      CSS has several options for which units to use when determining the size of various CSS properties. Learning all your options for CSS units can be key for styling in a way that’s easy to manage and looks great on any screen.

      What is a CSS Unit?

      A CSS unit determines the size of a property you’re setting for an element or its content. For example, if you wanted to set the property margin of a paragraph, you would give it a specific value. This value includes the CSS unit.

      Let’s look at a small example:

      p {
        margin: 20px;
      }
      

      In this case, margin is the property, 20px; is the value, and px (or “pixel”) is the CSS unit.

      Even though it’s common to see units like px used, the big question is often, “What’s the best unit to use here?”

      Here are some considerations to make when picking a unit type, and example use cases:


      Absolute vs. Relative Units

      When considering all the options for which units to use, it’s important to consider the two categories of units: absolute and relative.

      Absolute Units

      Units that are “absolute” are the same size regardless of the parent element or window size. This means a property set with a value that has an absolute unit will be that size when looked at on a phone or on a large monitor (and everything in between!)

      Absolute units can be useful when working on a project where responsiveness is not being considered. For example, desktop apps that can’t be resized can be styled for the default dimensions. If the window doesn’t scale, you don’t need the content to either.

      Hint: Absolute units can be less favourable for responsive sites because they don’t scale when the screen size changes.

      Absolute UnitDescriptionExample
      px1/96 of 1 inch (96px = 1 inch)font-size: 12px;
      pt1/72 of 1 inch (72pt = 1 inch)font-size: 12pt;
      pc12pt = 1pcfont-size: 1.2pc;
      cmcentimeterfont-size: 0.6cm;
      mmmillimeter (10 mm = 1 cm)font-size: 4mm;
      ininchesfont-size: 0.2in;

      Pixels (px) are typically the most popular absolute unit for screens. Centimeters, millimeters, and inches are more common for print and you may not have even known they were options!


      Relative Units

      Relative units are useful for styling responsive sites because they scale relative to the parent or window size (depending on the unit).

      As a general rule, relative units can be used as the default for responsive sites. This can help you avoid having to update styles for different screen sizes.

      Relative units can be a little more difficult than absolute units in determining which to use, so let’s go through your options in detail.

      Relative UnitDescription
      %Relative to the parent element’s value for that property
      emRelative to the current font-size of the element
      remRelative to the font-size of the root (e.g. the <html> element). “rem” = “root em”
      chNumber of characters (1 character is equal to the width of the current font’s 0/zero)
      vhRelative to the height of the viewport (window or app size). 1vh = 1/100 of the viewport’s height
      vwRelative to the width of viewport. 1vw = 1/100 of the viewport’s width.
      vminRelative to viewport’s smaller dimension (e.g. for portrait orientation, the width is smaller than the height so it’s relative to the width). 1vmin = 1/100 of viewport’s smaller dimension.
      vmaxRelative to viewport’s larger dimension (e.g. height for portrait orientation). 1vmax = 1/100 of viewport’s larger dimension.
      exRelative to height of the current font’s lowercase “x”.

      It’s not always clear which of these options is best to use for each type of CSS property. For example, % is usually more appropriate for layout-related properties like width than it would be for font-size.

      Here are some examples of when you would use each relative unit.

      • %: You want a child element to have 10% of the parent’s width as a margin so it never fills the whole parent element. If the parent’s size changes, the margin will update too.

        .child {
          margin: 10%;
        }
        
      • em: You want the font of a child element to be half the size of its parent’s font-size (e.g. the paragraph under a section’s title).

        .child {
          font-size: 0.5em;
        }
        
      • rem: The font-size should be twice the size as the root element’s font. This could be how you size your headers because they should all be the same size regardless of the parent container.

        .header {
          font-size: 2rem;
        }
        
      • ch: You have a mono-spaced font (the characters are always the same width) and you only have space for 10 characters.

        .small-text {
          width: 10ch;
        }
        
      • vh: Your landing page should always be the height of the viewport/window.

        .wrapper {
          height: 100vh;
        }
        
      • vw: You have a section with text that should be half as wide as the viewport/window.

        .half-size {
          width: 50vw;
        }
        
      • vmin: You have an image that should always be as wide as the viewport’s smaller dimension. On a phone being held in portrait mode, the image will be as wide as the viewport’s width.

        .min-width {
          width: 100vmin;
        }
        
      • vmax: You don’t care if an image gets cut off because you want it to completely fill the larger dimension of the viewport. For example, if an image of a pattern is used as a background.

        .max-width {
          width: 100vmax;
        }
        
      • ex: You probably won’t come across ex very often but it’s generally a good measure of a font’s mid-section. Let’s say you want to a font’s line-height to be double the height of the font’s “x”.

        .double-x {
          line-height: 2ex;
        }
        

      Overall, when and how you choose your CSS units will come down to a couple questions:

      • Do I want what I’m styling to scale when the viewport size changes?
      • If I do want it to scale, what do I want it to scale relative to in the app?

      Once you’ve answered these questions, it’s a lot easier to nail down which unit to use. 💪

      Further Reading

      You can dig deeper into viewport units by reading this article, or have a look at this article about em vs rem units if the difference between those two units is still somewhat unclear.



      Source link