PyPositron Docs

Style Class

The Style class represents the CSS style declaration of a DOM element. It provides a Python interface to directly manipulate CSS properties, allowing you to change the appearance and layout of HTML elements dynamically.

Overview

The Style class is accessed through the style property of any Element. It allows you to:

  • Set and get CSS properties using Python attribute syntax
  • Modify element appearance (colors, fonts, layout, etc.)
  • Create dynamic styling effects
  • Override CSS stylesheet rules

Usage

The Style class uses Python's __setattr__ and __getattr__ methods to provide a natural interface for CSS properties:

# Get an element
element = ui.document.getElementById("myElement")

# Set CSS properties
element.style.color = "red"
element.style.backgroundColor = "blue"
element.style.fontSize = "16px"
element.style.display = "none"

# Get CSS properties
current_color = element.style.color
current_display = element.style.display

Methods

  • __setattr__(name: str, value: str): Sets a CSS style property. The property name should be in camelCase (e.g., backgroundColor instead of background-color).
  • __getattr__(name: str) -> str: Gets the current value of a CSS style property.

CSS Properties Reference

CSS properties in the Style class use camelCase naming convention. Here are the most commonly used properties organized by category:

Layout Properties

Display and Positioning

  • display: Controls how an element is displayed (e.g., "block", "inline", "flex", "grid", "none")
  • position: Sets the positioning method (e.g., "static", "relative", "absolute", "fixed", "sticky")
  • top, right, bottom, left: Sets the position of a positioned element
  • zIndex: Sets the stack order of an element

Box Model

  • width, height: Sets element dimensions
  • minWidth, minHeight: Sets minimum dimensions
  • maxWidth, maxHeight: Sets maximum dimensions
  • margin: Sets margin (shorthand for all sides)
  • marginTop, marginRight, marginBottom, marginLeft: Sets individual margins
  • padding: Sets padding (shorthand for all sides)
  • paddingTop, paddingRight, paddingBottom, paddingLeft: Sets individual padding
  • boxSizing: Controls how the total width and height are calculated

Flexbox Layout

  • display: Set to "flex" to enable flexbox
  • flexDirection: Sets the direction of flex items (e.g., "row", "column")
  • justifyContent: Aligns flex items horizontally (e.g., "center", "space-between")
  • alignItems: Aligns flex items vertically (e.g., "center", "stretch")
  • flexWrap: Controls whether flex items wrap
  • flex: Shorthand for flex-grow, flex-shrink, and flex-basis

Grid Layout

  • display: Set to "grid" to enable grid layout
  • gridTemplateColumns: Defines grid columns
  • gridTemplateRows: Defines grid rows
  • gridGap: Sets gaps between grid items
  • gridColumn: Places an item in grid columns
  • gridRow: Places an item in grid rows

Text Properties

Font Styling

  • color: Sets text color
  • fontSize: Sets font size (e.g., "16px", "1.2em", "large")
  • fontFamily: Sets font family (e.g., "Arial, sans-serif")
  • fontWeight: Sets font weight (e.g., "normal", "bold", "400", "700")
  • fontStyle: Sets font style (e.g., "normal", "italic", "oblique")
  • fontVariant: Sets font variant (e.g., "normal", "small-caps")

Text Layout

  • textAlign: Sets text alignment (e.g., "left", "center", "right", "justify")
  • textDecoration: Sets text decoration (e.g., "none", "underline", "line-through")
  • textTransform: Controls text capitalization (e.g., "none", "uppercase", "lowercase", "capitalize")
  • lineHeight: Sets line height
  • letterSpacing: Sets spacing between characters
  • wordSpacing: Sets spacing between words
  • whiteSpace: Controls how whitespace is handled (e.g., "normal", "nowrap", "pre")
  • textOverflow: Controls how overflowed text is displayed (e.g., "clip", "ellipsis")

Background Properties

  • backgroundColor: Sets background color
  • backgroundImage: Sets background image (e.g., "url('image.jpg')")
  • backgroundSize: Controls background image size (e.g., "cover", "contain", "100px 50px")
  • backgroundPosition: Sets background image position (e.g., "center", "top left")
  • backgroundRepeat: Controls background image repetition (e.g., "repeat", "no-repeat")
  • backgroundAttachment: Sets whether background scrolls with content (e.g., "scroll", "fixed")

Border Properties

  • border: Sets border (shorthand for width, style, and color)
  • borderWidth: Sets border width
  • borderStyle: Sets border style (e.g., "solid", "dashed", "dotted", "none")
  • borderColor: Sets border color
  • borderRadius: Sets rounded corners
  • borderTop, borderRight, borderBottom, borderLeft: Sets individual borders
  • borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth: Sets individual border widths
  • borderTopStyle, borderRightStyle, borderBottomStyle, borderLeftStyle: Sets individual border styles
  • borderTopColor, borderRightColor, borderBottomColor, borderLeftColor: Sets individual border colors

Visual Effects

Opacity and Visibility

  • opacity: Sets transparency level (0.0 to 1.0)
  • visibility: Sets visibility (e.g., "visible", "hidden", "collapse")

Shadows and Filters

  • boxShadow: Adds shadow to element box
  • textShadow: Adds shadow to text
  • filter: Applies visual effects (e.g., "blur(5px)", "brightness(0.5)")

Transformations

  • transform: Applies 2D/3D transformations (e.g., "rotate(45deg)", "scale(1.5)")
  • transformOrigin: Sets transformation origin point

Animation and Transitions

  • transition: Creates smooth transitions between property changes
  • transitionProperty: Specifies which properties to animate
  • transitionDuration: Sets transition duration
  • transitionTimingFunction: Sets transition timing function
  • transitionDelay: Sets transition delay

Scroll and Overflow

  • overflow: Controls content overflow (e.g., "visible", "hidden", "scroll", "auto")
  • overflowX: Controls horizontal overflow
  • overflowY: Controls vertical overflow

Cursor and User Interaction

  • cursor: Sets cursor style (e.g., "pointer", "default", "wait", "not-allowed")
  • userSelect: Controls text selection (e.g., "none", "text", "all")
  • pointerEvents: Controls pointer events (e.g., "auto", "none")

Usage Examples

Basic Styling

def main(ui):
    button = ui.document.getElementById("myButton")
    
    # Basic appearance
    button.style.backgroundColor = "#007bff"
    button.style.color = "white"
    button.style.border = "none"
    button.style.padding = "10px 20px"
    button.style.borderRadius = "5px"
    button.style.cursor = "pointer"
    
    # Typography
    button.style.fontSize = "16px"
    button.style.fontWeight = "600"
    button.style.fontFamily = "Arial, sans-serif"

Responsive Layout with Flexbox

def main(ui):
    container = ui.document.getElementById("container")
    
    # Create a flexible layout
    container.style.display = "flex"
    container.style.flexDirection = "row"
    container.style.justifyContent = "space-between"
    container.style.alignItems = "center"
    container.style.padding = "20px"
    container.style.gap = "15px"
    
    # Make it responsive
    container.style.flexWrap = "wrap"

Hover Effects

def main(ui):
    card = ui.document.getElementById("card")
    
    def on_mouse_enter():
        card.style.transform = "scale(1.05)"
        card.style.boxShadow = "0 10px 20px rgba(0,0,0,0.2)"
        card.style.transition = "all 0.3s ease"
    
    def on_mouse_leave():
        card.style.transform = "scale(1)"
        card.style.boxShadow = "0 2px 5px rgba(0,0,0,0.1)"
    
    card.addEventListener("mouseenter", on_mouse_enter)
    card.addEventListener("mouseleave", on_mouse_leave)
    
    # Initial styling
    card.style.transition = "all 0.3s ease"
    card.style.cursor = "pointer"

Dynamic Theme Switching

def main(ui):
    def apply_dark_theme():
        body = ui.document.body
        body.style.backgroundColor = "#1a1a1a"
        body.style.color = "#ffffff"
        
        # Style all cards
        cards = ui.document.getElementsByClassName("card")
        for card in cards:
            card.style.backgroundColor = "#2d2d2d"
            card.style.borderColor = "#444"
            card.style.color = "#ffffff"
    
    def apply_light_theme():
        body = ui.document.body
        body.style.backgroundColor = "#ffffff"
        body.style.color = "#000000"
        
        cards = ui.document.getElementsByClassName("card")
        for card in cards:
            card.style.backgroundColor = "#ffffff"
            card.style.borderColor = "#ddd"
            card.style.color = "#000000"
    
    # Theme toggle button
    theme_btn = ui.document.getElementById("themeToggle")
    is_dark = False
    
    def toggle_theme():
        nonlocal is_dark
        if is_dark:
            apply_light_theme()
            theme_btn.innerText = "Dark Mode"
        else:
            apply_dark_theme()
            theme_btn.innerText = "Light Mode"
        is_dark = not is_dark
    
    theme_btn.addEventListener("click", toggle_theme)

Form Validation Styling

def main(ui):
    def validate_input(input_element, is_valid):
        if is_valid:
            input_element.style.borderColor = "#28a745"
            input_element.style.backgroundColor = "#f8fff9"
        else:
            input_element.style.borderColor = "#dc3545"
            input_element.style.backgroundColor = "#fff5f5"
    
    email_input = ui.document.getElementById("email")
    
    def check_email():
        email = email_input.value
        is_valid = "@" in email and "." in email
        validate_input(email_input, is_valid)
    
    email_input.addEventListener("input", check_email)
    
    # Initial styling
    email_input.style.transition = "all 0.3s ease"
    email_input.style.padding = "10px"
    email_input.style.border = "2px solid #ddd"
    email_input.style.borderRadius = "4px"

Loading Animation

def main(ui):
    spinner = ui.document.getElementById("spinner")
    
    # Create a spinning animation using CSS
    spinner.style.width = "40px"
    spinner.style.height = "40px"
    spinner.style.border = "4px solid #f3f3f3"
    spinner.style.borderTop = "4px solid #3498db"
    spinner.style.borderRadius = "50%"
    spinner.style.animation = "spin 2s linear infinite"
    
    # You would need to add the @keyframes rule to your CSS:
    # @keyframes spin {
    #   0% { transform: rotate(0deg); }
    #   100% { transform: rotate(360deg); }
    # }
    
    def show_loading():
        spinner.style.display = "block"
    
    def hide_loading():
        spinner.style.display = "none"
    
    # Example usage
    load_btn = ui.document.getElementById("loadBtn")
    
    def handle_load():
        show_loading()
        # Simulate loading time
        ui.htmlwindow.setTimeout(hide_loading, 3000)
    
    load_btn.addEventListener("click", handle_load)

Grid Layout

def main(ui):
    gallery = ui.document.getElementById("gallery")
    
    # Create a responsive grid
    gallery.style.display = "grid"
    gallery.style.gridTemplateColumns = "repeat(auto-fit, minmax(200px, 1fr))"
    gallery.style.gridGap = "20px"
    gallery.style.padding = "20px"
    
    # Add items to the grid
    for i in range(12):
        item = ui.document.createElement("div")
        item.className = "gallery-item"
        item.innerText = f"Item {i + 1}"
        
        # Style each item
        item.style.backgroundColor = "#f0f0f0"
        item.style.padding = "20px"
        item.style.textAlign = "center"
        item.style.borderRadius = "8px"
        item.style.transition = "transform 0.3s ease"
        
        # Add hover effect
        def create_hover_handler(element):
            def on_hover():
                element.style.transform = "translateY(-5px)"
                element.style.boxShadow = "0 5px 15px rgba(0,0,0,0.1)"
            def on_leave():
                element.style.transform = "translateY(0)"
                element.style.boxShadow = "none"
            
            element.addEventListener("mouseenter", on_hover)
            element.addEventListener("mouseleave", on_leave)
        
        create_hover_handler(item)
        gallery.appendChild(item)

CSS Property Name Conversion

When using CSS properties in PyPositron, remember to convert kebab-case to camelCase:

CSS Property PyPositron Style Property
background-color backgroundColor
font-size fontSize
margin-top marginTop
border-radius borderRadius
z-index zIndex
text-align textAlign
line-height lineHeight
box-shadow boxShadow

Best Practices

  1. Use meaningful units: Prefer px for precise measurements, em or rem for scalable text, % for responsive layouts.

  2. Set transitions for smooth effects: Always add transition properties when creating hover effects or dynamic style changes.

  3. Cache style references: If you're making multiple style changes, consider caching the style object:

    style = element.style
    style.color = "red"
    style.fontSize = "16px"
    style.padding = "10px"
    
  4. Use CSS classes for complex styling: For complex styles, consider adding/removing CSS classes instead of setting individual properties.

  5. Be mindful of performance: Changing many style properties can trigger layout recalculations. Group changes when possible.

  6. Validate color values: Ensure color values are valid CSS colors (hex, rgb, rgba, named colors).

  7. Use consistent units: Stick to consistent units throughout your application (e.g., always use px for borders).

Related Resources