Maxim
Maxim

Reputation: 9961

Why -fx-border-color reset border radius of TextField?

I want to change background and border color of TextField use JavaFX CSS. I don't understand why -fx-border-color reset border radius of TextField?

enter image description here

As you can see the second TextField doesn't have border radius.

sample/style.css:

.validation-error {
    -fx-background-color: #FFF0F0;
    -fx-border-color: #DBB1B1;
}

sample/Main.java

package sample;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        TextField txtWithoutStyle = new TextField();
        txtWithoutStyle.setText("Without Style");

        TextField txtWithStyle = new TextField();
        txtWithStyle.setText("With Style");
        txtWithStyle.getStyleClass().add("validation-error");

        VBox root = new VBox();
        root.setPadding(new Insets(14));
        root.setSpacing(14);
        root.getChildren().addAll(txtWithoutStyle, txtWithStyle);
        root.getStylesheets().add("/sample/style.css");

        Scene scene = new Scene(root, 300, 275);

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Update 1

Additional question: Why -fx-background-color remove TextField border (just remove -fx-border-color from style.css to reproduce it)?

Upvotes: 3

Views: 7176

Answers (1)

James_D
James_D

Reputation: 209398

The default stylesheet applies borders to text fields (and almost all other controls) by using "nested backgrounds" instead of borders.

Some of the settings for the TextInputControl from the default stylesheet are:

-fx-background-color: linear-gradient(to bottom, derive(-fx-text-box-border, -10%), -fx-text-box-border),
    linear-gradient(from 0px 0px to 0px 5px, derive(-fx-control-inner-background, -9%), -fx-control-inner-background);
-fx-background-insets: 0, 1;
-fx-background-radius: 3, 2;

This basically sets two background colors (both defined by a linear gradient), one (the "outer" one) with a color based on -fx-text-box-border, and the other with a color based on -fx-control-inner-background. The "outer" background is outside the "inner" background because they have insets of 0 and 1, respectively; the curved edge to the resulting apparent border is created by having radii of 3 and 2 for each background, respectively.

This is, anecdotally at least, far more efficient than using actual borders in the CSS, so this choice of technique is for performance reasons.

So to preserve the radius for the border, you can use the same technique, and just override the two background colors:

.validation-error {
    -fx-background-color: #DBB1B1, #FFF0F0 ;
 }

Note that you can also just replace the "looked-up-colors", which would also preserve the subtle linear gradients being used:

.validation-error {
    -fx-text-box-border: #DBB1B1 ;
    -fx-control-inner-background: #FFF0F0 ;
  }

For highlighting when focused, the default uses colors named -fx-focus-color and -fx-faint-focus-color: so in the latter version you would probably want to redefine those too:

.validation-error {
    -fx-text-box-border: #DBB1B1 ;
    -fx-control-inner-background: #FFF0F0 ;
    -fx-focus-color: #FF2020 ;
    -fx-faint-focus-color: #FF202020 ;
  }

Upvotes: 7

Related Questions